/*
 * Copyright (c) 2017 Hitevision
 */

package tw.com.hitevision.whiteboard.android;

import android.Manifest;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.Instrumentation;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.media.MediaActionSound;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.provider.MediaStore;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.GestureDetector;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewPropertyAnimator;
import android.view.ViewStub;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.bumptech.glide.Glide;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.load.resource.bitmap.DownsampleStrategy;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.CustomTarget;
import com.bumptech.glide.request.target.Target;
import com.bumptech.glide.request.transition.Transition;
import com.hht.sdk.client.APIManager;
import com.hht.wbdraw.IDrawService;
import com.hht.wbjni.WbJniCall;
import com.internal.i.solution.touch.IsTouchManager;

import net.glxn.qrgen.android.QRCode;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.ConstraintSet;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;
import androidx.core.graphics.drawable.DrawableCompat;

import hht.lib.xmsf.HHTCommand;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import tw.com.hitevision.whiteboard.android.Crawler.BrowserCrawler;
import tw.com.hitevision.whiteboard.android.display.BacklightManager;
import tw.com.hitevision.whiteboard.android.display.DisplayControl;
import tw.com.hitevision.whiteboard.android.display.DisplayControlImpl;
import tw.com.hitevision.whiteboard.android.display.DisplayControlNewlineChina;
import tw.com.hitevision.whiteboard.android.display.DisplayManager;
import tw.com.hitevision.whiteboard.android.fastdraw.FastDraw;
import tw.com.hitevision.whiteboard.android.navigator.Item;
import tw.com.hitevision.whiteboard.android.options.OptionsRecyclerViewAdapter;
import tw.com.hitevision.whiteboard.android.receivers.HhtActionBroadcastReceiver;
import tw.com.hitevision.whiteboard.android.render.EraserAreaView;
import tw.com.hitevision.whiteboard.android.render.Word;
import tw.com.hitevision.whiteboard.android.screenshot.ScreenshotHelper;
import tw.com.hitevision.whiteboard.android.state.AutoshapeProperty;
import tw.com.hitevision.whiteboard.android.state.HighlighterProperty;
import tw.com.hitevision.whiteboard.android.state.LineProperty;
import tw.com.hitevision.whiteboard.android.state.PageProperty;
import tw.com.hitevision.whiteboard.android.state.PenProperty;
import tw.com.hitevision.whiteboard.android.state.WhiteboardState;
import tw.com.hitevision.whiteboard.android.state.WordProperty;
import tw.com.hitevision.whiteboard.android.stateFile.GsonInstance;
import tw.com.hitevision.whiteboard.android.stateFile.JsonHandler;
import tw.com.hitevision.whiteboard.android.stateFile.StateFileSaver;
import tw.com.hitevision.whiteboard.android.stateFile.WhiteboardStateFile;
import tw.com.hitevision.whiteboard.android.storage.FileHandler;
import tw.com.hitevision.whiteboard.android.storage.FileHelper;
import tw.com.hitevision.whiteboard.android.util.ActivityUtils;
import tw.com.hitevision.whiteboard.android.util.BroadcastHelper;
import tw.com.hitevision.whiteboard.android.util.FileShareUtils;
import tw.com.hitevision.whiteboard.android.util.GlideApp;
import tw.com.hitevision.whiteboard.android.util.InputManager;
import tw.com.hitevision.whiteboard.android.util.SurfaceControlUtils;
import tw.com.hitevision.whiteboard.android.util.SystemPropertiesUtils;
import tw.com.hitevision.whiteboard.android.util.TouchUtils;
import tw.com.hitevision.whiteboard.android.widgets.AutoshapeMenuView;
import tw.com.hitevision.whiteboard.android.widgets.EraserMenuView;
import tw.com.hitevision.whiteboard.android.widgets.ExitAlertView;
import tw.com.hitevision.whiteboard.android.widgets.FloatingBarView;
import tw.com.hitevision.whiteboard.android.widgets.HighlighterMenuView;
import tw.com.hitevision.whiteboard.android.widgets.ImageToolbarMenuView;
import tw.com.hitevision.whiteboard.android.widgets.FrontSurfaceView;
import tw.com.hitevision.whiteboard.android.widgets.MeasurementTools.BasicRuler;
import tw.com.hitevision.whiteboard.android.widgets.MeasurementTools.MeasurementToolLayer;
import tw.com.hitevision.whiteboard.android.widgets.MeasurementTools.MeasurementToolListener;
import tw.com.hitevision.whiteboard.android.widgets.MeasurementTools.Protractor;
import tw.com.hitevision.whiteboard.android.widgets.MeasurementTools.Ruler;
import tw.com.hitevision.whiteboard.android.widgets.MeasurementTools.RulerTriangle;
import tw.com.hitevision.whiteboard.android.widgets.ModifiedEditTextForSkia;
import tw.com.hitevision.whiteboard.android.widgets.NavigatorView;
import tw.com.hitevision.whiteboard.android.widgets.NavigatorViewQRCodeDownloadDialog;
import tw.com.hitevision.whiteboard.android.widgets.NavigatorViewQRCodeExportDialog;
import tw.com.hitevision.whiteboard.android.widgets.OptionsRulerMenuView;
import tw.com.hitevision.whiteboard.android.widgets.PageMenuView;
import tw.com.hitevision.whiteboard.android.widgets.PenMenuView;
import tw.com.hitevision.whiteboard.android.widgets.PluginsToolbarMenuView;
import tw.com.hitevision.whiteboard.android.widgets.QRCodeDialog;
import tw.com.hitevision.whiteboard.android.widgets.SearchImageView;
import tw.com.hitevision.whiteboard.android.widgets.SelectionView;
import tw.com.hitevision.whiteboard.android.widgets.SettingsMenuView;
import tw.com.hitevision.whiteboard.android.widgets.WhiteboardDialog;
import tw.com.hitevision.whiteboard.android.widgets.WordMenuView;
import tw.com.hitevision.whiteboard.android.youtube.searchView.YoutubeSearchView;

import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import static tw.com.hitevision.whiteboard.android.widgets.OptionsRulerMenuAdapter.RULER;
import static tw.com.hitevision.whiteboard.android.widgets.OptionsRulerMenuAdapter.PROTRACTOR_DEGREE_180;
import static tw.com.hitevision.whiteboard.android.widgets.OptionsRulerMenuAdapter.PROTRACTOR_DEGREE_360;
import static tw.com.hitevision.whiteboard.android.widgets.OptionsRulerMenuAdapter.TRIANGLE_PROTRACTOR_RULER;
import static tw.com.hitevision.whiteboard.android.widgets.OptionsRulerMenuAdapter.TRIANGLE_RULER_30;
import static tw.com.hitevision.whiteboard.android.widgets.OptionsRulerMenuAdapter.TRIANGLE_RULER_45;

/**
 * This is the initial {@code Activity} called on app start.
 */
public class MainActivity extends BaseActivity implements SurfaceHolder.Callback,
        Whiteboard.Listener, SelectionView.Listener, NavigatorView.Listener, FrontSurfaceView.OnSurfaceViewCallBack,
        ImageToolbarMenuView.ImageToolbarTrigger, SearchImageView.SearchViewListener, ExitAlertView.Listener,
        PluginsToolbarMenuView.PluginsListener, SettingsMenuView.Listener,
        StateFileSaver.LoadJsonToStateFileListener {
    private static final String TAG = MainActivity.class.getSimpleName();

    /**
     * Set as {@code true} to start in annotation mode.  Default is {@code false}.
     */
    public static final String EXTRA_ANNOTATION_MODE = "extraAnnotationMode";
    /**
     * Set as {@code true} to hide app.  Default is {@code false}.
     */
    public static final String EXTRA_HIDE_APP = "extraHideApp";
    /**
     * Set as {@code true} to exit app without screenshot.  Default is {@code false}.
     */
    public static final String EXTRA_END_MEETING = "extraEndMeeting";
    private static final String MULTITOUCH_TEST_PACKAGE_NAME = "tw.com.hitevision.multitouchtest";
    private static final String MULTITOUCH_TEST_CLASS_NAME = "tw.com.hitevision.multitouchtest.MainActivity";

    private static final int REQUEST_GET_IMAGE = 1;
    private static final int REQUEST_GET_CUSTOM_BACKGROUND = 2;

    private static final int REQUEST_PERMISSION_WRITE_STORAGE = 1;
    private static final int REQUEST_PERMISSION_READ_STORAGE = 2;

    private static final long LOAD_NAVIGATOR_DELAY = 150; // ms
    private static final long ADD_PAGE_DELAY = 1000; // ms
    private static final long CHANGE_PAGE_DELAY = 1000; // ms
    private static final int pageChangesLimit = 10;

//    private static final long DELAY_STOP_PAINT_MANAGER = 500; // ms

    private static final int MAX_CHECK_TOGGLE_CONTROL_COUNT = 5;
    private static final long CHECK_TOGGLE_CONTROL_DELAY = 100; // ms

    private static final long DELAY_RESTORE_ROOT_ALPHA = 50; // ms

    private static final int UI_CHANGE_DELAY_4K = 500;
    private static final int UI_CHANGE_DELAY_2K = 160;

    /**
     * Maximum time interval between back presses before quitting.
     */
    private long backPressConfirmInterval;

    private int maxNumWhiteboardStates;

    private List<WhiteboardState> states;
    private WhiteboardState annotationState;
    public static int stateIndex;

    private RenderThread thread;
    private ScheduledExecutorService pool;
    private Whiteboard whiteboard;
    private Handler handler;
    private SurfaceView surface;
    private FrontSurfaceView frontSurfaceView;

    private List<View> inputGroup;
    private ImageView inputAutoshape;
    private View inputMoveCanvas;
    private View inputEraser;
    private View inputHighlighter;
    private View inputPen;
    private View inputSelect;
    private ImageView inputText;
    private ImageView penStroke;
    private ImageView highlighterStroke;

    private ImageView addImage;
    private ImageView plugins;
    private View addPage;
    private View backPage;
    private View nextPage;
    private View navigator;
    private View toggleBar;
    private View toggleControl;
    private View takeScreenshot;
    private View settings;
    private View oemAnnotationSettings;

    private View bottomBarBackground;
    private View switchMode;
    private View clearAll;
    private View undo;
    private ImageView redo;

    private View toastBackground;

    private WindowManager windowManager;
    private WindowManager.LayoutParams windowMangerParams;

    private View paste;
    private FloatingBarView floatingBarView;
    private FloatingBarView.FloatingBarListener floatingBarListener;

    private ModifiedEditTextForSkia wordDelegate;

    private TextView pageNumber;
    private TextView buildInfo;
    private View buildInfoButton;

    private PenMenuView penMenuView;
    private HighlighterMenuView highlighterMenuView;
    private AutoshapeMenuView autoshapeMenuView;
    private WordMenuView wordMenuView;
    private PageMenuView pageMenuView;
    private WhiteboardDialog dialog;
    private SelectionView selectionView;
    private NavigatorView navigatorView;
    private SettingsMenuView settingsMenuView;
    private EraserMenuView eraserMenuView;
    private ExitAlertView exitAlertView;
    private OptionsRulerMenuView optionsRulerMenuView;

    private DisplayManager displayManager;
    private DisplayControl displayControl;
    private DisplayControlNewlineChina displayControlNChina;
    private boolean isDisplayControlModeEnabled;

    private ScreenshotHelper screenshotHelper;
    private boolean isAutoScreenshotEnabled;

    /**
     * Time of last back press.
     */
    private long lastBackPressTime;

    private HandlerThread fileHandlerThread;
    private FileHandler fileHandler;
    private FileHelper fileHelper;

    private HandlerThread jsonHandlerThread;
    private JsonHandler jsonHandler;
    private StateFileSaver stateFileSaver;

    private PenProperty whiteboardFingerPenProp;
    private PenProperty whiteboardStylusPenProp;
    private HighlighterProperty whiteboardFingerHighlighterProp;
    private HighlighterProperty whiteboardStylusHighlighterProp;

    private PenProperty annotationFingerPenProp;
    private PenProperty annotationStylusPenProp;
    private HighlighterProperty annotationFingerHighlighterProp;
    private HighlighterProperty annotationStylusHighlighterProp;

    private PenProperty fingerPenProp;
    private PenProperty stylusPenProp;
    private HighlighterProperty fingerHighlighterProp;
    private HighlighterProperty stylusHighlighterProp;
    private AutoshapeProperty autoshapeProp;
    private WordProperty wordProp;
    private PageProperty pageProp;

    private BacklightManager backlightManager;
    private boolean isWritingEyeProtectionEnabled;

    private FastDraw fastDraw;
    private boolean isCleanBufferRequired;

    private MediaActionSound actionSound;

    private boolean isFinishing;
    private boolean isOnCreateOrOnNewIntentCalled;

    private Toast lastToast;
    private int pageChanges;

    private ImageToolbarMenuView imageToolbarMenuView;
    private PluginsToolbarMenuView pluginsToolbarMenuView;

    private SearchImageView searchImageView;
    private BrowserCrawler browserCrawler;
    private YoutubeSearchView youtubeSearchView;

    private View share;
    private View exit;

    private Settings mSettings;

    // matrix for textbox calculation
    private Matrix mat;

    private String lastScreenshotFileName;

    private SearchThumbnailsTask searchThumbnailsTask;
    private List<Target> targetList;

    private boolean isTakingScreenshot;

    private int checkToggleControlCount;

    private int floatingBarInsetLeft;
    private int floatingBarInsetTop;
    private int floatingBarInsetBottom;

    private int wordDefaultWidth;

    private HhtActionBroadcastReceiver hhtActionBroadcastReceiver;
    private HhtActionBroadcastReceiver hhtActionBroadcastSplitMenuReceiver;
    private HhtActionBroadcastReceiver hhtActionBroadcastFloatingCursorReceiver;
    private boolean isInTouchGesture;

    private boolean hasRequestedStorageWritePermission;
    private boolean hasRequestedStorageReadPermission;

    private QRCodeDialog qrCodeDialog;
    private boolean isActivityVisible;

    private View oemBottomBarRightDivider;
    private View oemBottomBarLeftDivider;
    private View oemAnnotationBackground;

    private Target<Drawable> backgroundTarget;


    private boolean restartApp;
    private View jsonBlockingView;
    private View jsonAlertView;

    private IDrawService mIDrawService;

    private EraserAreaView eraserAreaView;
    private boolean partialEraserDone = true;

    private NavigatorViewQRCodeExportDialog exportDialog;
    private NavigatorViewQRCodeDownloadDialog exportQRCodeDownloadDialog;

    private ImageView exitWhiteboard;
    private ViewStub lineSurfaceViewViewStub;
    private ViewStub selectionViewViewStub;
    private ViewStub settingsMenuViewViewStub;
    private ViewStub pluginsToolbarMenuViewViewStub;
    private ViewStub penMenuViewViewStub;
    private ViewStub highLighterMenuViewViewStub;
    private ViewStub autoShapeMenuViewViewStub;
    private ViewStub wordMenuViewViewStub;
    private ViewStub pageMenuViewViewStub;
    private ViewStub imageToolBarMenuViewViewStub;
    private ViewStub whiteboardDialogViewStub;
    private ViewStub navigatorViewViewStub;
    private ViewStub searchImageViewViewStub;
    private ViewStub jsonLoadBlockingImageViewViewStub;
    private ViewStub jsonAlertViewViewStub;
    private ViewStub eraserMenuViewViewStub;
    private ViewStub viewStubTutorialMenu;
    private ViewStub viewStubRulerMenuView;
    private ViewStub youtubeSearchViewStub;

    private ImageView fakeBackground;
    private boolean isFirstStart = true;
    private boolean clearSplitMenu = true;

    private View floatingCursorView;
    private ImageView floatingCursorFloatingCursorView;
    private ImageView floatingCursorAddAutoshapeView;
    private ImageView floatingCursorPenStroke;
    private ImageView floatingCursorHighlighterStroke;

    //處理“白板分屏模式下回主页后再进入白板会退出分屏模式”
    public final static String EXIT_SPLIT_MENU = "exitSplitMenu";
    private boolean exitSplitMenu = true;

    public void setExitSplitMenu(boolean exitSplitMenu) {
        if (Props.getFlavorModel().equals(Props.Flavor.Model.Oem) && Props.getFlavorChipset().equals(Props.Flavor.Chipset.Hisi))//19C 白板分屏模式下回主页后再进入白板会退出分屏模式
            this.exitSplitMenu = exitSplitMenu;
    }

    public boolean isExitSplitMenu() {
        return exitSplitMenu;
    }

    private Ruler ruler;
    private RulerTriangle rulerTriangle45;
    private RulerTriangle rulerTriangle30;
    private RulerTriangle rulerTriangleProtractor;
    private MeasurementToolLayer measurementToolLayer;
    private Protractor protractor180;
    private Protractor protractor360;

    private String curSourceTouchChannel;

    Handler Myhandler = new Handler() {
        @Override
        public void dispatchMessage(@NonNull Message msg) {

            if (msg.what == 100) { //9666
                cancelFastDraw();
            }

            if (msg.what == 101) { //9666
                SystemPropertiesUtils.setValue(SystemPropertiesUtils.KEY_FRAME_BUFFER_LOCK, "0");
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        log("onCreate");
        /*zf for move whiteboard apk to background*/
        moveWhiteboardToBackground();
        registerHhtActionBroadcastOpenSplitMenuReceiver();
        registerHhtActionBroadcastFloatingCursorReceiver();
        mSettings = Settings.getInstance(this);
        if (mSettings.getReloadWhiteboardJson()) {
            mSettings.setReloadWhiteboardJson(false);
            showLoadJsonDialog();
        }
        // TODO : debug
//        mSettings.setReloadWhiteboardJson(true);
        isAutoScreenshotEnabled = mSettings.getAutoScreenshotIsEnabled();
        if (mSettings.isFake4k()) {
            changeDPI(3);
//            windowMangerParams = getWindow().getAttributes();
//            windowMangerParams.setTitle("ist_win_editdialog");
//            windowMangerParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
//            windowMangerParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
//            getWindow().setAttributes(windowMangerParams);
        }

        setContentView(R.layout.activity_main);

        isOnCreateOrOnNewIntentCalled = true;
        isFirstStart = true;

        // get intent extras
        final Intent i = getIntent();
        if (i.getBooleanExtra(EXTRA_END_MEETING, false)) {
            finish();
            return;
        }
        if (i.getBooleanExtra(EXTRA_HIDE_APP, false)) {
            // make sure float bar doesn't disappear
            BroadcastHelper.sendScreenshotEndAndAppIsFinishing(this);
            isFinishing = true;
            finish();
            return;
        }
        boolean annotationMode = i.getBooleanExtra(EXTRA_ANNOTATION_MODE, false);

        // get constants from resources
        Resources res = getResources();
        backPressConfirmInterval = res.getInteger(R.integer.back_press_confirm_interval);
        maxNumWhiteboardStates = res.getInteger(R.integer.max_number_of_whiteboard_states);
        floatingBarInsetLeft = res.getDimensionPixelSize(R.dimen.floating_bar_inset_left);
        floatingBarInsetTop = res.getDimensionPixelSize(R.dimen.floating_bar_inset_top);
        floatingBarInsetBottom = res.getDimensionPixelSize(R.dimen.floating_bar_inset_bottom);
        wordDefaultWidth = res.getDimensionPixelSize(R.dimen.word_default_width);

        displayManager = DisplayManager.getInstance();
        displayControl = DisplayControl.newInstance(this);
        displayControlNChina = new DisplayControlNewlineChina();

        screenshotHelper = new ScreenshotHelper(this);

        targetList = new ArrayList<>();

        surface = findViewById(R.id.surface_view);
        surface.setZOrderMediaOverlay(true);
        surface.setOnTouchListener(new SurfaceViewOnTouchListener(this));

        final SurfaceHolder holder = surface.getHolder();
        holder.addCallback(this);
        holder.setFormat(PixelFormat.TRANSLUCENT);

        fileHandlerThread = new HandlerThread("fileIoThread");
        fileHandlerThread.start();
        fileHandler = new FileHandler(this, fileHandlerThread.getLooper());
        fileHelper = FileHelper.getInstance(this);

        jsonHandlerThread = new HandlerThread("handleJsonInThread");
        jsonHandlerThread.start();
        jsonHandler = new JsonHandler(this, jsonHandlerThread.getLooper());

        stateFileSaver = StateFileSaver.getInstance(this);
        stateFileSaver.reset();
        stateFileSaver.setListener(this);

        initProps();

        annotationState = new WhiteboardState(PageProperty.Color.TRANSPARENT,
                PageProperty.Pattern.BLANK, null, null, true);

        states = new ArrayList<>(maxNumWhiteboardStates);
        stateIndex = 0;
        WhiteboardState state;
        if (Props.getFlavorModel().equals(Props.Flavor.Model.Wcd)) {
            state = annotationState;
            annotationMode = true;
        } else if (Props.getFlavorModel().equals(Props.Flavor.Model.Oem)) {
            if (annotationMode) {
                state = annotationState;
            } else {
                state = new WhiteboardState(pageProp.getColor(),
                        pageProp.getPattern(), pageProp.getCustomBackground(),
                        fileHelper.generateFileName(false), false);
                states.add(state);
            }
        } else {
            if (annotationMode) {
                state = annotationState;
            } else {
                state = new WhiteboardState(pageProp.getColor(),
                        pageProp.getPattern(), pageProp.getCustomBackground(),
                        fileHelper.generateFileName(false), false);
//                state = new WhiteboardState(mSettings.getPageMenuSettingColorEnum(),
//                        mSettings.getPageMenuSettingPatternEnum(), pageProp.getCustomBackground(),
//                        fileHelper.generateFileName(false), false);
                states.add(state);
            }
        }

        fastDraw = new FastDraw(this, state, annotationMode);

//        whiteboard = new Whiteboard(this, fileHandler, fastDraw, state);
        whiteboard = new Whiteboard(this, fileHandler, fastDraw, jsonHandler, state, getBaseContext());
        whiteboard.setListener(this);
        whiteboard.setAutoshapeProperty(autoshapeProp);
        whiteboard.setWordProperty(wordProp);

        thread = new RenderThread(whiteboard, holder, fastDraw);

        initViews();

        if (switchMode != null) {
            switchMode.setSelected(annotationMode);
        }
        setAppMode(annotationMode);
        try {
            browserCrawler = new BrowserCrawler(this.getApplicationContext());
        } catch (Exception e) {
            e.printStackTrace();
        }

        try {
            APIManager.connectionService(this);
        } catch (Exception e) {
            e.printStackTrace();
        }

        hhtActionBroadcastReceiver = new HhtActionBroadcastReceiver(hhtActionListener);
        hhtActionBroadcastSplitMenuReceiver = new HhtActionBroadcastReceiver(hhtActionListener);
        hhtActionBroadcastFloatingCursorReceiver = new HhtActionBroadcastReceiver(hhtActionListener);

        if (Props.getMainboardVersion() != Props.Mainboard.V_811 && Props.isPaintHelperEnabled()
                && !Props.getFlavorChipset().equals(Props.Flavor.Chipset.Optoma)) {
            connectToFastDrawAIDL();
        }

        handler = new Handler();
        //to avoid image offset before setting surface size
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                if (i.getParcelableExtra("rect") != null) {
                    getImageRectFromIntent(i);
                }

                //add by jay
                Uri shortPathUri = i.getData();
                if (shortPathUri != null) {
                    String type = i.getType();
                    Log.d("jay", "---handler---type=" + type);
                    if (!TextUtils.isEmpty(type)) {
                        if (type.equals("image/*")) {
                            String path = shortPathUri.getPath();
                            Log.d("jay", "---handler---inputPath=" + path);
                            if (!TextUtils.isEmpty(path)) {
                                getFilePathFromIntent(path);
                            }
                        }
                    }
                }
                //end

                String intentFilePath = i.getStringExtra(FileHelper.FILE_PATH);
                if (intentFilePath != null && !intentFilePath.isEmpty()) {
                    getFilePathFromIntent(intentFilePath);
                }
            }
        }, 0);

        postSurfaceChangedRunnable = () -> {
            if (mSettings.getFlagNeedTutorial()) {
                viewStubTutorialMenu.inflate();
            }

            initSelectionView();
            initSearchImageView();
            initEraserMenuView();
            setRenderThreadFutureTask();
            initYoutubeSearchView();
        };

        //批注模式下Android点选，初始化floatingCursor悬浮窗
        initFloatingCursorWindow();

//        handler.postDelayed(() -> {
//            // delay doing
//
//            thread.setPaused(false);
//
//            // maybe have problem
//            initSelectionView();
////            initSettingsMenuView();
////            initPluginsToolbarMenuView();
////            initPenMenuView();
////            initHighLighterMenuView();
////            initAutoShapeMenuView();
////            initWordMenuView();
////            initPageView();
////            initImageToolbarMenuView();
////            initWhiteboardDialogView();
//            // maybe have problem
////            initNavigatorView();
//            initSearchImageView();
////            initJsonLoadBlockingImageView();
//            initEraserMenuView();
//
//            setRenderThreadFutureTask();
//        }, 1000);

        if (backlightManager == null) {
            backlightManager = new BacklightManager(getApplicationContext());
        }

        new Handler().postDelayed(new Runnable() {
            @SuppressLint("ResourceAsColor")
            @Override
            public void run() {
                Log.d("zf", "run: init hi");
                if (highlighterMenuView == null) {
                    initHighLighterMenuView();
                }
                highlighterMenuView.colors.get(3).callOnClick();

            }
        }, 500);
    }

    private Runnable postSurfaceChangedRunnable;

    private final ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName name, IBinder service) {
            MainActivity.this.mIDrawService = IDrawService.Stub.asInterface(service);
            if (fastDraw != null) {
                fastDraw.setIDrawService(mIDrawService);
                log("Connect AIDL service success");
            } else {
                log("Connect AIDL service failed");
            }

//            try {
//                MainActivity.this.iDrawServiceInterface.fbSetPaintColor(-65536, 0);
//                MainActivity.this.iDrawServiceInterface.fbSetPaintStrokeWidth(10.0F, 0);
//                MainActivity.this.iDrawServiceInterface.fbMoveTo(100.0F, 100.0F, 0, 0);
//            } catch (RemoteException var4) {
//                var4.printStackTrace();
//            }

        }

        public void onServiceDisconnected(ComponentName name) {
            MainActivity.this.mIDrawService = null;
            fastDraw.setIDrawService(null);
        }
    };

    private void moveWhiteboardToBackground() {
        Intent intent = new Intent();
        intent.setAction("uc.hht.whiteboard.Annotation_On");
        sendBroadcast(intent);
    }

    private void connectToFastDrawAIDL() {
        Intent intent = new Intent();
        intent.setAction("com.hht.DrawService");
        intent.setPackage("com.hht.wbserver");
        this.startService(intent);
        this.bindService(intent, this.mConnection, Context.BIND_AUTO_CREATE);
    }

    private void initProps() {

        final int penWhite = ContextCompat.getColor(this, R.color.pen_white);
        final int penRed = ContextCompat.getColor(this, R.color.pen_red);
        final int penBlack = ContextCompat.getColor(this, R.color.pen_black);
        final int highlighterYellow = ContextCompat.getColor(this, R.color.highlight_yellow);
        final int highlighterRed = ContextCompat.getColor(this, R.color.highlight_red);
        final int yello = ContextCompat.getColor(this, R.color.pen_yellow);

        autoshapeProp = new AutoshapeProperty(AutoshapeProperty.Type.ARROW, AutoshapeProperty.Color.WHITE);
        wordProp = new WordProperty(WordProperty.TextColor.WHITE, WordProperty.DEFAULT_SIZE);

        if (Props.getFlavorModel().equals(Props.Flavor.Model.Oem)) {
            whiteboardFingerPenProp = new PenProperty(penWhite, PenProperty.Size.ONE);
            whiteboardStylusPenProp = new PenProperty(penWhite, PenProperty.Size.ONE);
            whiteboardFingerHighlighterProp = new HighlighterProperty(yello, HighlighterProperty.Size.TWO);
            whiteboardFingerHighlighterProp = new HighlighterProperty(highlighterYellow, HighlighterProperty.Size.TWO);
            whiteboardStylusHighlighterProp = new HighlighterProperty(highlighterYellow, HighlighterProperty.Size.TWO);

            annotationFingerPenProp = new PenProperty(penRed, PenProperty.Size.ONE);
            annotationStylusPenProp = new PenProperty(penRed, PenProperty.Size.ONE);
//            annotationFingerHighlighterProp = new HighlighterProperty(highlighterYellow, HighlighterProperty.Size.TWO);
            annotationFingerHighlighterProp = new HighlighterProperty(yello, HighlighterProperty.Size.TWO);
            annotationStylusHighlighterProp = new HighlighterProperty(highlighterYellow, HighlighterProperty.Size.TWO);

            pageProp = new PageProperty(PageProperty.Color.GREEN, PageProperty.Pattern.BLANK);
        } else {
            whiteboardFingerPenProp = new PenProperty(penRed, PenProperty.Size.ONE);
            whiteboardStylusPenProp = new PenProperty(penWhite, PenProperty.Size.ONE);
            whiteboardFingerHighlighterProp = new HighlighterProperty(highlighterYellow, HighlighterProperty.Size.TWO);
            whiteboardStylusHighlighterProp = new HighlighterProperty(highlighterYellow, HighlighterProperty.Size.TWO);

            annotationFingerPenProp = new PenProperty(penRed, PenProperty.Size.ONE);
            annotationStylusPenProp = new PenProperty(penBlack, PenProperty.Size.ONE);
            annotationFingerHighlighterProp = new HighlighterProperty(highlighterYellow, HighlighterProperty.Size.TWO);
            annotationStylusHighlighterProp = new HighlighterProperty(highlighterYellow, HighlighterProperty.Size.TWO);

            pageProp = new PageProperty(PageProperty.Color.BLUE, PageProperty.Pattern.BLANK);
        }
    }

    private void moveTaskToFront() {
        if (Props.getFlavorChipset().equals(Props.Flavor.Chipset.Amlogic)) {
            Intent intent = new Intent();
            intent.setComponent(new ComponentName("tw.com.hitevision.whiteboard", "tw.com.hitevision.whiteboard.android.MainActivity"));
            intent.putExtra(EXTRA_ANNOTATION_MODE, true);
            startActivity(intent);
        } else {
            final ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
            activityManager.moveTaskToFront(this.getTaskId(), ActivityManager.MOVE_TASK_NO_USER_ACTION);//该flag会连带返回Android主页面
        }
    }

    private void setFloatingCursorDeviceInput(Device device, View button) {
        log("setFloatingCursorDeviceInput: device=" + device);
        Whiteboard.Input input = null;
        switch (button.getId()) {
            case R.id.input_pen_: {
                input = Whiteboard.Input.PEN;
                break;
            }
            case R.id.input_highlighter_: {
                input = Whiteboard.Input.HIGHLIGHTER;
                break;
            }
            case R.id.add_autoshape_: {
                input = Whiteboard.Input.AUTOSHAPE;
                break;
            }
            case R.id.input_select_: {
                input = Whiteboard.Input.SELECT;
                break;
            }
            case R.id.input_eraser_: {
                if (eraserMenuView.getCurMode() == EraserMenuView.EraserMode.OBJECT) {
                    input = Whiteboard.Input.OBJECT_ERASER;
                } else {
                    input = Whiteboard.Input.PARTIAL_ERASER;
                }
                break;
            }
        }
        if (button.getId() == R.id.input_highlighter_) {
            FastDraw.isHighliter = true;
        } else {
            FastDraw.isHighliter = false;
        }
        log("setFloatingCursorDeviceInput：- input=" + input);
        if (input != null) {
            whiteboard.queueInput(InputEvent.createInputChangeAction(device, input));
        }
    }

    /**
     * 设置input属性
     */
    @SuppressLint("ClickableViewAccessibility")
    private final View.OnTouchListener floatingCursorToggleInputTouchListener = (v, event) -> {
        final int action = event.getActionMasked();
        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP) {
            Device device = TouchUtils.getEventDevice(this, event.getActionIndex(), event);
            if (device == Device.PALM) {
                device = Device.FINGER;
            }
            setFloatingCursorDeviceInput(device, v);
            switch (device) {
                case FINGER: {
                    updatePenUi(fingerPenProp);
                    updateHighlighterUi(fingerHighlighterProp);
                    if (penMenuView != null) {
                        penMenuView.setSize(fingerPenProp.getSize());
                        penMenuView.setColor(fingerPenProp.getColor());
                    }
                    if (highlighterMenuView != null) {
                        highlighterMenuView.setSize(fingerHighlighterProp.getSize());
                        highlighterMenuView.setColor(fingerHighlighterProp.getColor());
                    }
                    if (floatingBarView != null) {
                        floatingBarView.updatePenUi(fingerPenProp);
                        floatingBarView.updateHighlighterUi(fingerHighlighterProp);

                        floatingBarView.setPenMenuProp(fingerPenProp);
                        floatingBarView.setHighlighterMenuProp(fingerHighlighterProp);
                    }
                    break;
                }
                case STYLUS: {
                    updatePenUi(stylusPenProp);
                    updateHighlighterUi(stylusHighlighterProp);
                    if (penMenuView != null) {
                        penMenuView.setSize(stylusPenProp.getSize());
                        penMenuView.setColor(stylusPenProp.getColor());
                    }
                    if (highlighterMenuView != null) {
                        highlighterMenuView.setSize(stylusHighlighterProp.getSize());
                        highlighterMenuView.setColor(stylusHighlighterProp.getColor());
                    }
                    if (floatingBarView != null) {
                        floatingBarView.updatePenUi(stylusPenProp);
                        floatingBarView.updateHighlighterUi(stylusHighlighterProp);

                        floatingBarView.setPenMenuProp(stylusPenProp);
                        floatingBarView.setHighlighterMenuProp(stylusHighlighterProp);
                    }
                    break;
                }
            }
        }
        return false;
    };

    /**
     * gone自定义悬浮窗并将批注移到前台
     */
    private void goneFloatingCursorWindow() {
        floatingCursorView.setVisibility(View.GONE);
        moveTaskToFront();
    }

    /**
     * 19B 鼠标悬浮窗
     */
    private void initFloatingCursorWindow() {
        if (!Props.getFlavorModel().equals(Props.Flavor.Model.Oem))
            return;
        log("*********************initWindow*****************");
        floatingCursorView = LayoutInflater.from(this).inflate(R.layout.floating_cursor, null);
        floatingCursorView.setVisibility(View.GONE);
        floatingCursorView.setFocusableInTouchMode(true);
        WindowManager.LayoutParams arrowWindowMangerParams;
        arrowWindowMangerParams = new WindowManager.LayoutParams();
        arrowWindowMangerParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY + 1;
        arrowWindowMangerParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;// | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        arrowWindowMangerParams.format = PixelFormat.TRANSLUCENT;
        arrowWindowMangerParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
        arrowWindowMangerParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
        arrowWindowMangerParams.x = 0;
        arrowWindowMangerParams.y = getWindowManager().getDefaultDisplay().getHeight() / 2;
        if (Props.isFake4k()) {
            arrowWindowMangerParams.x = -270;
            arrowWindowMangerParams.y = 0;
        }
        if (null == windowManager) {
            windowManager = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
        }
        windowManager.addView(floatingCursorView, arrowWindowMangerParams);
        floatingCursorView.setOnKeyListener(new View.OnKeyListener() {//监听返回键，退出进程
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                if (keyCode == KeyEvent.KEYCODE_BACK && KeyEvent.ACTION_DOWN == event.getAction()) {
                    MainActivity.this.onBackPressed();
                    return true;
                }
                return false;
            }
        });

        floatingCursorAddAutoshapeView = floatingCursorView.findViewById(R.id.add_autoshape_);
        floatingCursorPenStroke = floatingCursorView.findViewById(R.id.pen_stroke_);
        floatingCursorHighlighterStroke = floatingCursorView.findViewById(R.id.highlighter_stroke_);
        floatingCursorFloatingCursorView = floatingCursorView.findViewById(R.id.floating_cursor);
        floatingCursorFloatingCursorView.setOnClickListener(v -> {
            goneFloatingCursorWindow();
        });

        /*************************设置菜单选择及相应属性start*************************************/
        View floatingCursorInputPenView = floatingCursorView.findViewById(R.id.input_pen_);
        floatingCursorInputPenView.setOnClickListener(v -> {
            goneFloatingCursorWindow();
            if (!inputPen.isSelected())
                inputPen.performClick();//设置页面显示
        });
        floatingCursorInputPenView.setOnTouchListener(floatingCursorToggleInputTouchListener);

        View floatingCursorInputHighlighterView = floatingCursorView.findViewById(R.id.input_highlighter_);
        floatingCursorInputHighlighterView.setOnClickListener(v -> {
            goneFloatingCursorWindow();
            if (!inputHighlighter.isSelected())
                inputHighlighter.performClick();
        });
        floatingCursorInputHighlighterView.setOnTouchListener(floatingCursorToggleInputTouchListener);

        floatingCursorAddAutoshapeView.setOnClickListener(v -> {
            goneFloatingCursorWindow();
            inputAutoshape.performClick();
        });
        floatingCursorAddAutoshapeView.setOnTouchListener(floatingCursorToggleInputTouchListener);

        ImageView floatingCursorInputSelectView = floatingCursorView.findViewById(R.id.input_select_);
        floatingCursorInputSelectView.setOnClickListener(v -> {
            goneFloatingCursorWindow();
            if (!inputSelect.isSelected())
                inputSelect.performClick();
        });
        floatingCursorInputSelectView.setOnTouchListener(floatingCursorToggleInputTouchListener);

        ImageView floatingCursorInputEraserView = floatingCursorView.findViewById(R.id.input_eraser_);
        floatingCursorInputEraserView.setOnClickListener(v -> {
            goneFloatingCursorWindow();
            if (!inputEraser.isSelected())
                inputEraser.performClick();
        });
        floatingCursorInputEraserView.setOnTouchListener(floatingCursorToggleInputTouchListener);

        ImageView floatingCursorClearScreenView = floatingCursorView.findViewById(R.id.clear_screen_);
        floatingCursorClearScreenView.setOnClickListener(v -> {
            goneFloatingCursorWindow();
            clearAll.performClick();
        });

        ImageView floatingCursorUndoView = floatingCursorView.findViewById(R.id.undo_);
        floatingCursorUndoView.setOnClickListener(v -> {
            goneFloatingCursorWindow();
            undo.performClick();
        });

        ImageView floatingCursorRedoView = floatingCursorView.findViewById(R.id.redo_);
        floatingCursorRedoView.setOnClickListener(v -> {
            goneFloatingCursorWindow();
            redo.performClick();
        });

        ImageView floatingCursorTakeScreenshotView = floatingCursorView.findViewById(R.id.take_screenshot_);
        floatingCursorTakeScreenshotView.setOnClickListener(v -> {
            goneFloatingCursorWindow();
            takeScreenshot.performClick();
        });
        floatingCursorTakeScreenshotView.setOnLongClickListener(v -> {
            goneFloatingCursorWindow();
            hideMenus();
            showAutoScreenshotDialog();
            return true;
        });

        ImageView floatingCursorOemAnnotationSettingsView = floatingCursorView.findViewById(R.id.oem_annotation_settings_);
        floatingCursorOemAnnotationSettingsView.setOnClickListener(v -> {
            goneFloatingCursorWindow();
            oemAnnotationSettings.performClick();
        });

        ImageView floatingCursorFinishView = floatingCursorView.findViewById(R.id.finish_);
        floatingCursorFinishView.setOnClickListener(v -> {
            goneFloatingCursorWindow();
            exit.performClick();
        });
        /*************************设置菜单选择及相应属性end*************************************/

    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if ((keyCode == KeyEvent.KEYCODE_BACK) && searchImageView != null && searchImageView.getVisibility() == View.VISIBLE) {
            boolean result = searchImageView.backKeyHandle();
//            inputSearch.setSelected(result);
            return true;
        }

        return super.onKeyDown(keyCode, event);
    }

    private void cancelFastDraw() {
        log("cancelFastDraw");
        boolean cleanFrameBuffer = false;
        if (fastDraw != null && fastDraw.isDrawing()) {
            handler.removeCallbacks(runStopFastDraw);
            fastDraw.stop();
            cleanFrameBuffer = true;
        }
        if (cleanFrameBuffer || isCleanBufferRequired) {
//            whiteboard.queueInput(InputEvent.createAction(InputEvent.Action.CLEAN_FRAME_BUFFER));
//            isCleanBufferRequired = false;

            handler.removeCallbacks(restoreRootAlphaRunnable);
            findViewById(android.R.id.content).setAlpha(0.99f);
            handler.postDelayed(restoreRootAlphaRunnable, DELAY_RESTORE_ROOT_ALPHA);
        }
    }

    private Runnable restoreRootAlphaRunnable = () -> {
        findViewById(android.R.id.content).setAlpha(1.0f);
    };

    /**
     * 判断TLiveTV界面是否在先前一层
     *
     * @param context
     * @return
     */
    public static boolean isTLiveTVForeground(Context context) {
        ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        String runningActivity = activityManager.getRunningTasks(2).get(1).baseActivity.getClassName();
        Log.d("yls", "isTLiveTVForeground: " + runningActivity);
        return runningActivity.contains("com.hht.source.activity") || runningActivity.contains("com.hisilicon.tvui.play.MainActivity");
    }

    /**
     * 判断是在Android还是OPS下使用白板（批注）
     *
     * @param intent
     * @return
     */
    private boolean currentSourceIsOPS(Intent intent) {
        if (!Props.getFlavorModel().equals(Props.Flavor.Model.Oem))
            return false;
        if (null == intent)
            intent = getIntent();
        if (isTLiveTVForeground(this) && intent.getBooleanExtra(EXTRA_ANNOTATION_MODE, false))
            return true;
        return false;
    }

    private void initViews() {
        inputGroup = new ArrayList<>();
        if ((SystemPropertiesUtils.getStringValue(SystemPropertiesUtils.KEY_8386_19A_OR_19B, "0").contains(Props.OEM_Model.MODEL_19B)
                && !FastDraw.isSupportedCanvasFastDrawEraser())
                || Props.getFlavorChipset().equals(Props.Flavor.Chipset.Optoma)
        ) {
            lineSurfaceView();
        }

        if (Props.getFlavorModel().equals(Props.Flavor.Model.Oem)) {
            oemBottomBarRightDivider = findViewById(R.id.oem_annotation_bar_right_divider);
            oemBottomBarLeftDivider = findViewById(R.id.oem_annotation_bar_left_divider);
            oemAnnotationBackground = findViewById(R.id.oem_annotation_bottom_bar);
        }

        switchMode = findViewById(R.id.switch_mode);
        if (switchMode != null) {
            switchMode.setOnClickListener(new View.OnClickListener() {
                private View otherModeInput;

                @Override
                public void onClick(View v) {
                    switchMode.setEnabled(false);

                    v.setSelected(!v.isSelected());

                    final boolean isSelected = v.isSelected();

                    if (!isSelected && states.isEmpty()) {
                        WhiteboardState state = new WhiteboardState(pageProp.getColor(),
                                pageProp.getPattern(), pageProp.getCustomBackground(),
                                fileHelper.generateFileName(false), false);
                        states.add(state);
                    }

                    setAppMode(isSelected);

                    final View currentInput = getCurrentInput();
                    if (otherModeInput == null) {
//                        otherModeInput = inputHighlighter;
                        // Cosam
                        otherModeInput = inputPen;
                    }
                    whiteboard.setShowText(otherModeInput == inputText);

                    toggleInput(otherModeInput);
                    otherModeInput = currentInput;

                    GlideApp.get(MainActivity.this.getApplicationContext()).clearMemory();
                    System.gc();

                    switchMode.postDelayed(() -> switchMode.setEnabled(true), CHANGE_PAGE_DELAY);

                    if (displayControl.isSupported(MainActivity.this)) {
                        if (isSelected) {
                            BroadcastHelper.sendSourceAppMuteOff(MainActivity.this);
                        } else {
                            BroadcastHelper.sendSourceAppMuteOn(MainActivity.this);
                        }
                    }

                    if (isSelected) {
                        updateStateJson(states.get(stateIndex), stateFileSaver.generateJsonFileName(stateIndex));
                    } else {
                        updateStateJson(annotationState, stateFileSaver.generateAnnotationJsonFileName());
                    }

                    cancelFastDraw();
                }
            });
        }

        addImage = findViewById(R.id.add_image);
        if (addImage != null) {
            addImage.setOnClickListener(v -> {
                if (Props.getPhase() >= Props.Phase.THREE || Props.getFlavorModel().equals(Props.Flavor.Model.Oem)) {
                    whiteboard.disableTrimmingMode();
                    if (imageToolbarMenuView == null) {
                        initImageToolbarMenuView();
                    }
                    if (imageToolbarMenuView.getVisibility() != View.VISIBLE) {
                        hideMenus();
                        imageToolbarMenuView.setVisibility(View.VISIBLE);
                        clearTextBoxAndToggleKeyboard();
                        clearSelection();
                    } else {
                        imageToolbarMenuView.setVisibility(View.GONE);
                    }
                } else {
                    clearTextBoxAndToggleKeyboard();
                    clearSelection();

                    whiteboard.queueInput(InputEvent.createGetReadyForSelectionModeAction(Whiteboard.CLEAR_TEXT_SELECTION_AREA_ACTION));

                    Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
                    intent.setType("image/*");
                    intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[]{"image/jpeg", "image/png", "image/bmp", "image/gif"});
                    if (intent.resolveActivity(getPackageManager()) != null) {
                        startActivityForResult(intent, REQUEST_GET_IMAGE);
                    }

                    hideMenus();

                }
            });
        }

        if (Props.getFlavorModel().equals(Props.Flavor.Model.Oem)) {
            plugins = findViewById(R.id.plungins);
            plugins.setOnClickListener(v -> {
                whiteboard.disableTrimmingMode();
                if (pluginsToolbarMenuView == null) {
                    initPluginsToolbarMenuView();
                }
                if (pluginsToolbarMenuView.getVisibility() != View.VISIBLE) {
                    hideMenus();
                    pluginsToolbarMenuView.setVisibility(View.VISIBLE);
                    clearTextBoxAndToggleKeyboard();
                    clearSelection();
                } else {
                    pluginsToolbarMenuView.setVisibility(View.GONE);
                }
            });
        }

        inputText = findViewById(R.id.add_text);
        if (inputText != null) {
            inputText.setOnClickListener(v -> {
                if (Props.getPhase() >= Props.Phase.THREE) {
                    whiteboard.disableTrimmingMode();
                }
                if (wordMenuView == null) {
                    initWordMenuView();
                }
                if (v.isSelected()) {
                    if (wordMenuView.getVisibility() != View.VISIBLE) {
                        hideMenus();
                        wordMenuView.setVisibility(View.VISIBLE);
                        clearTextBoxAndToggleKeyboard();
                        clearSelection();
                    } else {
                        wordMenuView.setVisibility(View.GONE);
                    }
                } else {
                    toggleInput(v);
                    hideMenus();
                    wordMenuView.setVisibility(View.VISIBLE);
                    clearTextBoxAndToggleKeyboard();
                    clearSelection();
                }
            });
            inputText.setOnTouchListener(toggleInputTouchListener);
        }

        inputAutoshape = findViewById(R.id.add_autoshape);
        if (inputAutoshape != null) {
            inputAutoshape.setOnClickListener(v -> {
                if (Props.getPhase() >= Props.Phase.THREE) {
                    whiteboard.disableTrimmingMode();
                }
                if (autoshapeMenuView == null) {
                    log("2QQ");
                    initAutoShapeMenuView();
                }
                if (v.isSelected()) {
                    if (autoshapeMenuView.getVisibility() != View.VISIBLE) {
                        hideMenus();
                        autoshapeMenuView.setVisibility(View.VISIBLE);
                    } else {
                        autoshapeMenuView.setVisibility(View.GONE);
                    }
                } else {
                    toggleInput(v);
                    hideMenus();
                    autoshapeMenuView.setVisibility(View.VISIBLE);
                    clearTextBoxAndToggleKeyboard();
                    clearSelection();
                }
            });
            inputAutoshape.setOnTouchListener(toggleInputTouchListener);
        }

        inputMoveCanvas = findViewById(R.id.move_canvas);
        if (inputMoveCanvas != null) {
            inputMoveCanvas.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    hideMenus();
                    if (v.isSelected()) {
                        // TODO : maybe need to back to previous input
                    } else {
                        toggleInput(v);
                        clearTextBoxAndToggleKeyboard();
                        clearSelection();
                    }
                }
            });
            if (!Props.getFlavorModel().equals(Props.Flavor.Model.Oem)) {
                inputMoveCanvas.setVisibility(View.GONE);
            }
            inputMoveCanvas.setOnTouchListener(toggleInputTouchListener);
        }

        inputPen = findViewById(R.id.input_pen);
        inputPen.setOnClickListener(v -> {
            if (floatingBarView != null) {
                floatingBarView.syncInputFromMain(FloatingBarView.InputMode.PEN);
                floatingBarView.setVisibility(View.INVISIBLE);
            }
            if (v.isSelected()) {
                if (penMenuView == null) {
                    initPenMenuView();
                }
                if (penMenuView.getVisibility() != View.VISIBLE) {
                    hideMenus();
                    penMenuView.setVisibility(View.VISIBLE);
                } else {
                    penMenuView.setVisibility(View.GONE);
                }
            } else {
                toggleInput(v);
                hideMenus();
                clearTextBoxAndToggleKeyboard();
                clearSelection();
                if (Props.getPhase() >= Props.Phase.THREE) {
                    whiteboard.disableTrimmingMode();
                }
            }
        });
        inputPen.setOnTouchListener(toggleInputTouchListener);

        penStroke = findViewById(R.id.pen_stroke);

        inputHighlighter = findViewById(R.id.input_highlighter);
        inputHighlighter.setOnClickListener(v -> {
            if (Props.getPhase() >= Props.Phase.THREE) {
                whiteboard.disableTrimmingMode();
            }
            if (floatingBarView != null) {
                floatingBarView.syncInputFromMain(FloatingBarView.InputMode.HIGHLIGHTER);
                floatingBarView.setVisibility(View.INVISIBLE);
            }
            if (v.isSelected()) {
                if (highlighterMenuView == null) {
                    initHighLighterMenuView();
                }
                if (highlighterMenuView.getVisibility() != View.VISIBLE) {
                    hideMenus();
                    highlighterMenuView.setVisibility(View.VISIBLE);
                } else {
                    highlighterMenuView.setVisibility(View.GONE);
                }
            } else {
                toggleInput(v);

                hideMenus();
                clearTextBoxAndToggleKeyboard();
                clearSelection();
            }
        });
        inputHighlighter.setOnTouchListener(toggleInputTouchListener);

        highlighterStroke = findViewById(R.id.highlighter_stroke);

        inputSelect = findViewById(R.id.input_select);
        if (inputSelect != null) {
            inputSelect.setOnClickListener(v -> {
                if (Props.getPhase() >= Props.Phase.THREE) {
                    whiteboard.disableTrimmingMode();
                }
                toggleInput(v);
                hideMenus();
                clearTextBoxAndToggleKeyboard();
                whiteboard.update();
            });
            inputSelect.setOnTouchListener(toggleInputTouchListener);
        }
        eraserAreaView = findViewById(R.id.eraserAreaTest);
        inputEraser = findViewById(R.id.input_eraser);
        inputEraser.setOnClickListener(v -> {
//            if (Props.getPhase() >= Props.Phase.THREE) {
//                whiteboard.disableTrimmingMode();
//            }
            if (floatingBarView != null) {
                floatingBarView.syncInputFromMain(FloatingBarView.InputMode.ERASER);
                floatingBarView.setVisibility(View.INVISIBLE);
            }
            if (eraserMenuView == null) {
                initEraserMenuView();
            }
            if (v.isSelected()) {
                if (eraserMenuView.getVisibility() != View.VISIBLE) {
                    hideMenus();
                    eraserMenuView.setVisibility(View.VISIBLE);
                } else {
                    eraserMenuView.setVisibility(View.GONE);
                }
            } else {
                toggleInput(v);
                hideMenus();
                clearTextBoxAndToggleKeyboard();
                clearSelection();
            }
            eraserMenuView.notifyEraserInput();
        });
        inputEraser.setOnTouchListener(toggleInputTouchListener);

        clearAll = findViewById(R.id.clear_screen);
        clearAll.setOnClickListener(v -> {
            if (toggleControl != null && toggleControl.isSelected()) {
                toggleControl.callOnClick();
            }

            if (Props.getPhase() >= Props.Phase.THREE) {
                whiteboard.disableTrimmingMode();
            }
            clearTextBoxAndToggleKeyboard();
            clearSelection();
            confirmClearAll();

            if (floatingBarView != null) {
                if (getCurrentInput() == inputGroup.get(0)) {
                    floatingBarView.syncInputFromMain(FloatingBarView.InputMode.PEN);

                } else {
                    floatingBarView.syncInputFromMain(FloatingBarView.InputMode.HIGHLIGHTER);
                }
                floatingBarView.setVisibility(View.INVISIBLE);
            }

            hideMenus();
        });

        undo = findViewById(R.id.undo);
        undo.setOnClickListener(v -> {
            hideMenus();
            clearTextBoxAndToggleKeyboard();
            clearSelection();
            if (floatingBarView != null) {
                floatingBarView.setVisibility(View.INVISIBLE);
            }

            if (whiteboard.isTrimmingActive()) {
                if (selectionView != null) {
                    selectionView.activeTrimming(false);
                }
                if (Props.getPhase() >= Props.Phase.THREE) {
                    whiteboard.disableTrimmingMode();
                }
            }

            cancelFastDraw();

            whiteboard.queueInput(InputEvent.createAction(InputEvent.Action.UNDO));
        });

//        if (!Props.getFlavorModel().equals(Props.Flavor.Model.Oem)) {
        redo = findViewById(R.id.redo);
        redo.setOnClickListener(v -> {
            hideMenus();
            clearTextBoxAndToggleKeyboard();
            clearSelection();
            if (floatingBarView != null) {
                floatingBarView.setVisibility(View.INVISIBLE);
            }

            if (whiteboard.isTrimmingActive()) {
                if (selectionView != null) {
                    selectionView.activeTrimming(false);
                }
                if (Props.getPhase() >= Props.Phase.THREE) {
                    whiteboard.disableTrimmingMode();
                }
            }

            cancelFastDraw();

            whiteboard.queueInput(InputEvent.createAction(InputEvent.Action.REDO));
        });
//        }

        addPage = findViewById(R.id.add_page);
        if (addPage != null) {
            addPage.setOnClickListener(v -> {
                if (pageMenuView == null) {
                    initPageView();
                }
                if (pageMenuView.getVisibility() != View.VISIBLE) {
                    addPage.setEnabled(false);

                    if (Props.getPhase() >= Props.Phase.THREE) {
                        whiteboard.disableTrimmingMode();
                    }
                    clearTextBoxAndToggleKeyboard();
                    clearSelection();
                    cancelFastDraw();
                    addNewPage();
                    hideMenus();

                    addPage.postDelayed(() -> addPage.setEnabled(true), ADD_PAGE_DELAY);

                }
            });
            addPage.setOnLongClickListener(v -> {
                if (pageMenuView == null) {
                    initPageView();
                }
                if (pageMenuView.getVisibility() != View.VISIBLE) {
                    if (Props.getPhase() >= Props.Phase.THREE) {
                        whiteboard.disableTrimmingMode();
                    }
                    clearTextBoxAndToggleKeyboard();
                    clearSelection();
                    cancelFastDraw();
                    hideMenus();
                    pageMenuView.setVisibility(View.VISIBLE);
                }
                return true;
            });
        }

        backPage = findViewById(R.id.back_page);
        if (backPage != null) {
            backPage.setOnClickListener(v -> {
                nextPage.setEnabled(false);
                backPage.setEnabled(false);

                if (Props.getPhase() >= Props.Phase.THREE) {
                    whiteboard.disableTrimmingMode();
                }
                clearTextBoxAndToggleKeyboard();
                clearSelection();
                cancelFastDraw();
                backPage();
                clearTextBoxAndToggleKeyboard();
                hideMenus();

                backPage.postDelayed(() -> {
                    nextPage.setEnabled(true);
                    backPage.setEnabled(true);
                }, CHANGE_PAGE_DELAY);
            });
        }

        nextPage = findViewById(R.id.next_page);
        if (nextPage != null) {
            nextPage.setOnClickListener(v -> {
                nextPage.setEnabled(false);
                backPage.setEnabled(false);

                if (Props.getPhase() >= Props.Phase.THREE) {
                    whiteboard.disableTrimmingMode();
                }
                clearTextBoxAndToggleKeyboard();
                clearSelection();
                cancelFastDraw();
                nextPage();
                clearTextBoxAndToggleKeyboard();
                hideMenus();

                nextPage.postDelayed(() -> {
                    nextPage.setEnabled(true);
                    backPage.setEnabled(true);
                }, CHANGE_PAGE_DELAY);
            });
        }

        View.OnClickListener settingsOnClickLis = v -> {
            if (toggleControl != null && toggleControl.isSelected()) {
                toggleControl.callOnClick();
            }

            if (settingsMenuView == null) {
                initSettingsMenuView();
            }
            if (settingsMenuView.isVisible()) {
                settingsMenuView.hide();
            } else {
                if (Props.getPhase() >= Props.Phase.THREE) {
                    whiteboard.disableTrimmingMode();
                }
                hideMenus();
                settingsMenuView.show();
            }
        };

        settings = findViewById(R.id.settings);
        if (settings != null) {
            if (!Props.getFlavorChipset().equals(Props.Flavor.Chipset.Mstar)) {
                settings.setVisibility(View.GONE);
            }
            settings.setOnClickListener(settingsOnClickLis);
        }

        if (Props.getFlavorModel().equals(Props.Flavor.Model.Oem) && settings != null) {
            oemAnnotationSettings = findViewById(R.id.oem_annotation_settings);
            if (oemAnnotationSettings != null) {
                oemAnnotationSettings.setOnClickListener(settingsOnClickLis);
            }
        }

        if (checkIf_U_TypeTouch()) {
            settings.setVisibility(View.INVISIBLE);
            if (oemAnnotationSettings != null) {
                oemBottomBarLeftDivider.setVisibility(View.GONE);
            }
        }

        navigator = findViewById(R.id.navigator);
        if (navigator != null) {
            navigator.setOnClickListener(v -> {
                if (toggleControl != null && toggleControl.isSelected()) {
                    toggleControl.callOnClick();
                }
                if (Props.getPhase() >= Props.Phase.THREE) {
                    whiteboard.disableTrimmingMode();
                }
                hideMenus();
//                clearTextBoxAndToggleKeyboard();
                if (navigatorView == null) {
                    initNavigatorView();
                }
                if (navigatorView.isVisible()) {
                    navigatorView.hide();
                } else {
                    cancelFastDraw();

                    // update current state's preview
                    whiteboard.queueInput(InputEvent.createAction(InputEvent.Action.UPDATE_STATE_PREVIEW));
//                    navigatorView.setStates(states);
                    navigatorView.show();

                    // not ideal: pass states to navigatorView after a slight delay to allow for
                    // current state's preview to update
                    handler.postDelayed(() -> navigatorView.setStates(states, stateIndex), LOAD_NAVIGATOR_DELAY);
                }
            });
        }

        share = findViewById(R.id.share_screen);
        if (share != null) {
            share.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (floatingBarView != null) {
                        floatingBarView.setVisibility(View.INVISIBLE);
                    }
                    takeScreenshot(shareAfterAnimationListener);
                }
            });
        }

        exit = findViewById(R.id.finish);
        if (exit != null) {
            exit.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    exitAlertView.setEmptyExitDialogMode(whiteboard.isItemExists());
                    exitAlertView.setVisibility(View.VISIBLE);
                }
            });
        }

        toggleBar = findViewById(R.id.toggle_bar);
        if (toggleBar != null) {
            toggleBar.setOnClickListener(v -> {
                if (Props.getPhase() >= Props.Phase.THREE) {
                    whiteboard.disableTrimmingMode();
                }
                if (floatingBarView != null) {
                    floatingBarView.setVisibility(View.INVISIBLE);
                }
                v.setSelected(!v.isSelected());
                setBottomBarVisible(!v.isSelected());
                hideMenus();

            });
        }

        toggleControl = findViewById(R.id.display_control);
        if (toggleControl != null) {
            toggleControl.setOnClickListener(new View.OnClickListener() {
                private View lastInput;

                @Override
                public void onClick(View v) {
                    v.setSelected(!v.isSelected());
                    log("toggleControlClicked.");

                    final boolean isSelected = v.isSelected();

                    if (whiteboard.getState().isAnnotationState() && isActivityVisible) {
                        onNewIntentAnnotationMode();
                    } else {
                        onNewIntentHideApp();
                    }

                    if (isSelected) {
                        if (Props.getFlavorModel().equals(Props.Flavor.Model.Oem)
                                && (Props.getFlavorChipset().equals(Props.Flavor.Chipset.Mstar) || Props.getFlavorChipset().equals(Props.Flavor.Chipset.Hisi)
                                || Props.getFlavorChipset().equals(Props.Flavor.Chipset.Amlogic) || Props.getFlavorChipset().equals(Props.Flavor.Chipset.Optoma))
                                && !currentSourceIsOPS(null)) {//19B 批注在安卓下可切换至其他应用
                            floatingCursorView.setVisibility(View.VISIBLE);
                            moveTaskToBack(true);
                            floatingCursorAddAutoshapeView.setImageResource(autoshapeProp.getTypeDrawableRes());
                            floatingCursorPenStroke.setImageDrawable(penStroke.getDrawable());
                            floatingCursorHighlighterStroke.setImageDrawable(highlighterStroke.getDrawable());
                        }
                        // save currently selected input and clear it
                        lastInput = getCurrentInput();
                        if (lastInput != null) {
                            lastInput.setSelected(false);
                        }

                        clearSelection();
                        hideMenus();
                        /*by zf*/
                        if (Props.getFlavorChipset().equals(Props.Flavor.Chipset.Optoma)) {
//                            IsTouchManager.getInstance().setPublicUsbToTV(true, true);
//                            IsTouchManager.getInstance().setTouchChannelUSB(IsTouchManager.TOUCH_POSTPC, true);
                            IsTouchManager.getInstance().setTouchCmdConfig(7);
                        }
                    } else {
                        // restore last selected input
                        if (lastInput != null) {
                            lastInput.setSelected(true);
                        }
                        /*by zf*/
                        if (Props.getFlavorChipset().equals(Props.Flavor.Chipset.Optoma)) {
//                            IsTouchManager.getInstance().setPublicUsbToTV(true, true);
//                            IsTouchManager.getInstance().setTouchChannelUSB(curSourceTouchChannel, true);
                            IsTouchManager.getInstance().setTouchCmdConfig(8);
                        }
                    }
                    if (currentSourceIsOPS(null))//处理“批注在Android下点选崩溃问题”，setDisplayControlMode在ops下才使用
                        setDisplayControlMode(isSelected);
                    else
                        setDisplayControlMode(false);
                }
            });

            toggleControl.setVisibility(View.GONE);
        }

        takeScreenshot = findViewById(R.id.take_screenshot);
        takeScreenshot.setOnClickListener(v -> {
            /*use hht hht screenshot service*/
//            if(Props.getMainboardVersion() != Props.Mainboard.V_811)
//                NewMethodForTakeScrennShot();
//            else {
                if (Props.getPhase() >= Props.Phase.THREE) {
                    whiteboard.disableTrimmingMode();
                }
                clearTextBoxAndToggleKeyboard();
                clearSelection();
                hideMenus();
//                onClickTakeScreenshot(takeScreenshotAfterAnimationListener);  //wuxin-0417
                takeScreenshot(takeScreenshotAfterAnimationListener);   //wuxin+0417
                Log.d("wx", "MainActivity call onClickTakeScreenshot");
//            }
        });
        takeScreenshot.setOnLongClickListener(v -> {
            hideMenus();

            showAutoScreenshotDialog();
            return true;
        });

        //粘贴
        paste = findViewById(R.id.paste);
        if (paste != null) {
            paste.setTag(new PointF());
            paste.setOnClickListener(v -> {
                if (inputSelect != null) {
                    toggleInput(inputSelect);
                    setDeviceInput(Device.FINGER, inputSelect);
                }

                PointF point = (PointF) paste.getTag();
                whiteboard.queueInput(InputEvent.createAction(InputEvent.Action.PASTE, point.x, point.y));
                paste.setVisibility(View.GONE);
            });
        }

        bottomBarBackground = findViewById(R.id.bottom_bar_background);
        bottomBarBackground.setOnTouchListener((v, event) -> {

            if (floatingBarView != null) {
                floatingBarView.setVisibility(View.INVISIBLE);
            }
            return true; // don't pass touches on bottom bar to other views
        });


        wordDelegate = findViewById(R.id.word_delegate);
        if (wordDelegate != null) {
            wordDelegate.setWhiteboardLis(whiteboard);
            wordDelegate.addTextChangedListener(wordDelegateTextWatcher);
        }

        // set exclusive input group
        if (inputText != null) {
            inputGroup.add(inputText);
        }
        if (inputAutoshape != null) {
            inputGroup.add(inputAutoshape);
        }
        inputGroup.add(inputPen);
        inputGroup.add(inputHighlighter);
        if (inputSelect != null) {
            inputGroup.add(inputSelect);
        }
        inputGroup.add(inputEraser);
        if (Props.getPhase() >= Props.Phase.THREE) {
            if (addImage != null) {
                inputGroup.add(addImage);
            }
        }
        if (inputMoveCanvas != null) {
            inputGroup.add(inputMoveCanvas);
        }

        // select initial input
//        toggleInput(InputManager.getInstance().getInput(Device.FINGER) == Whiteboard.Input.HIGHLIGHTER
//                ? inputHighlighter : inputPen);
        // Cosam 2020/11/11 change the init select status to pen
        toggleInput(inputPen);

        floatingBarView = findViewById(R.id.floating_bar_view);
        if (floatingBarView != null) {
            floatingBarView.setPenProp(stylusPenProp);
            floatingBarView.setHighlighterProp(fingerHighlighterProp);
            floatingBarView.setToggleInputTouchListener(toggleInputTouchListener);
            floatingBarView.setPenMenuOnTouchListener(toggleInputTouchListener);
            floatingBarView.setHighlighterMenuOnTouchListener(toggleInputTouchListener);

            floatingBarListener = new FloatingBarView.FloatingBarListener() {


                // receive property from floatingBar
                @Override
                public void updateCurrentPenPropertyFromFloatingBar(Device device, int color, PenProperty.Size size) {
                    final PenProperty penProp = device == Device.FINGER ? fingerPenProp : stylusPenProp;
                    penProp.setColor(color);
                    penProp.setSize(size);
                    if (penMenuView != null) {
                        penMenuView.setColor(color);
                        penMenuView.setSize(size);
                    }
                    updatePenUi(penProp);
                    whiteboard.queueInput(InputEvent.createInputChangeAction(device, Whiteboard.Input.PEN));

                }

                @Override
                public void updateCurrentHighlighterPropertyFromFloatingBar(Device device, int color, HighlighterProperty.Size size) {
                    final HighlighterProperty highlighterProperty = device == Device.FINGER ? fingerHighlighterProp : stylusHighlighterProp;
                    highlighterProperty.setColor(color);
                    highlighterProperty.setSize(size);
                    if (highlighterMenuView != null) {
                        highlighterMenuView.setColor(color);
                        highlighterMenuView.setSize(size);
                    }
                    updateHighlighterUi(highlighterProperty);
                    whiteboard.queueInput(InputEvent.createInputChangeAction(device, Whiteboard.Input.HIGHLIGHTER));
                }

                @Override
                public void closeFloatingBar() {
                    floatingBarView.setVisibility(View.INVISIBLE);

                    if (isFinishing) {
                        // do nothing
                        return;
                    }

                    if (whiteboard.getState().isAnnotationState() && isAutoScreenshotEnabled) {
                        isFinishing = true;
                        takeScreenshot(finishAfterAnimationListener);
                    } else {
                        finish();
                    }
                }

                @Override
                public void takeFloatingBarScreenshot() {
                    floatingBarView.setVisibility(View.INVISIBLE);
                    floatingBarView.hideMenus();
                    takeScreenshot(takeScreenshotAfterAnimationListener);
                }

                @Override
                public void floatingBarUndo() {
                    whiteboard.queueInput(InputEvent.createAction(InputEvent.Action.UNDO));
                }

                @Override
                public void clearAll() {
                    floatingBarView.setVisibility(View.INVISIBLE);
                    floatingBarView.hideMenus();
                    clearAll.callOnClick();
                }

                @Override
                public void updateInputMode(int i) {
                    switch (i) {
                        case 0: {
                            toggleInput(inputPen);
                            break;
                        }
                        case 1: {
                            toggleInput(inputHighlighter);
                            break;
                        }
                        case 2: {
                            toggleInput(inputEraser);
                            break;
                        }
                        case 3: {
                            break;
                        }
                        default: {
                            break;
                        }
                    }
                }

                @Override
                public void onScreenshotSettingClick() {
                    floatingBarView.setVisibility(View.INVISIBLE);
                    floatingBarView.hideMenus();
                    showAutoScreenshotDialog();
                }

                @Override
                public void onShareScreenshotClick() {
                    floatingBarView.setVisibility(View.INVISIBLE);
                    floatingBarView.hideMenus();
                    takeScreenshot(shareAfterAnimationListener);
                }
            };
            floatingBarView.setFloatingBarListener(floatingBarListener);
        }

        pageNumber = findViewById(R.id.page_number);

        if (Props.getFlavorModel().equals(Props.Flavor.Model.Rs)) {
            qrCodeDialog = findViewById(R.id.qr_code_dialog);
        }

        exitAlertView = findViewById(R.id.exit_alert_view);
        exitAlertView.setListener(this);
        exitWhiteboard = findViewById(R.id.button_exit_whiteboard);
        exitWhiteboard.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                exitAlertView.setEmptyExitDialogMode(whiteboard.isItemExists());
                exitAlertView.setVisibility(View.VISIBLE);
            }
        });

        // get build info

        String versionName = null;
        int versionCode = 1;
        try {
            PackageInfo pInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
            versionName = pInfo.versionName;
            versionCode = pInfo.versionCode;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }

        buildInfo = findViewById(R.id.build_info);
        buildInfo.setText(String.format("%s (%s)", versionName, versionCode));

        buildInfoButton = findViewById(R.id.build_info_trigger);
        buildInfoButton.setOnClickListener(buildInfoOnClickListener);

        // allow long press to finish app when in debug build
        if (BuildConfig.DEBUG) {
            buildInfoButton.setOnTouchListener(new View.OnTouchListener() {
                private static final long LONG_PRESS_DURATION = 5000L;

                private final Runnable finish = () -> finish();

                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    switch (event.getActionMasked()) {
                        case MotionEvent.ACTION_DOWN: {
                            v.postDelayed(finish, LONG_PRESS_DURATION);
                            break;
                        }
                        case MotionEvent.ACTION_UP:
                        case MotionEvent.ACTION_CANCEL: {
                            v.removeCallbacks(finish);
                            break;
                        }
                    }
                    return false;
                }
            });
        }

        View renderDebugTrigger = findViewById(R.id.render_debug_trigger);
        renderDebugTrigger.setOnClickListener(renderTestClickListener);
        findViewById(R.id.render_debug_view).setOnClickListener(v -> {
            v.setVisibility(View.INVISIBLE);
            thread.setDebugListener(null);
        });

        hideMenus();

        selectionViewViewStub = findViewById(R.id.view_stub_selection_controls);
        settingsMenuViewViewStub = findViewById(R.id.view_stub_settings_menu_view);
        pluginsToolbarMenuViewViewStub = findViewById(R.id.view_stub_plugins_toolbar_menu_view);
        penMenuViewViewStub = findViewById(R.id.view_stub_pen_menu_view);
        highLighterMenuViewViewStub = findViewById(R.id.view_stub_highlighter_menu_view);
        autoShapeMenuViewViewStub = findViewById(R.id.view_stub_auto_shape_menu_view);
        wordMenuViewViewStub = findViewById(R.id.view_stub_word_menu_view);
        pageMenuViewViewStub = findViewById(R.id.view_stub_page_menu_view);
        imageToolBarMenuViewViewStub = findViewById(R.id.view_stub_image_toolbar_menu_view);
        whiteboardDialogViewStub = findViewById(R.id.view_stub_whiteboard_dialog_view);
        navigatorViewViewStub = findViewById(R.id.view_stub_navigator_view);
        searchImageViewViewStub = findViewById(R.id.view_stub_search_image_view);
        jsonLoadBlockingImageViewViewStub = findViewById(R.id.view_stub_json_load_blocking_image_view);
        jsonAlertViewViewStub = findViewById(R.id.view_stub_json_alert_view);
        eraserMenuViewViewStub = findViewById(R.id.view_stub_eraser_menu_view);
        viewStubTutorialMenu = findViewById(R.id.viewstub_tutorial_menu);
        youtubeSearchViewStub = findViewById(R.id.view_stub_search_youtube_view);
        viewStubRulerMenuView = findViewById(R.id.view_stub_ruler_menu_view);

        fakeBackground = findViewById(R.id.fake_background);
//        fakeBackground.setBackgroundResource(whiteboard.getState().getPageColorRes());
        fakeBackground.setBackgroundResource(R.color.page_black);
        if (whiteboard.getState().getPagePatternRes() != 0) {
            Glide.with(this).load(ContextCompat.getDrawable(this, whiteboard.getState().getPagePatternRes())).into(fakeBackground);
        }
        fakeBackground.setOnTouchListener((v, event) -> false);
    }

    private void doFinish() {
        if (isFinishing) {
            // do nothing
            return;
        }
        isFinishing = true;
        cancelFastDraw();

        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                if (whiteboard.getState().isAnnotationState() && isAutoScreenshotEnabled) {
                    takeScreenshot(finishAfterAnimationListener);
                } else {
                    finish();
                }
            }
        }, 500);
    }

    private void lineSurfaceView() {
        if (frontSurfaceView != null) {
            return;
        }
        lineSurfaceViewViewStub = findViewById(R.id.view_stub_line_surface_view);
        lineSurfaceViewViewStub.inflate();
        frontSurfaceView = findViewById(R.id.line_surface_view);
        frontSurfaceView.setZOrderMediaOverlay(true);
        frontSurfaceView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
        frontSurfaceView.registerCallBack(this);
        if (Props.getFlavorChipset().equals(Props.Flavor.Chipset.Optoma))
            frontSurfaceView.setFastDraw(fastDraw);
    }

    private void initSelectionView() {
        if (selectionView != null) {
            return;
        }
        selectionViewViewStub.inflate();
        selectionView = findViewById(R.id.selection_controls);
        selectionView.setListener(this);
        selectionView.hide();
    }

    private void initSettingsMenuView() {
        if (settingsMenuView != null) {
            return;
        }
        settingsMenuViewViewStub.inflate();
        settingsMenuView = findViewById(R.id.settings_menu);
        settingsMenuView.setVisibility(GONE);
        settingsMenuView.setListener(this);
//        if (whiteboard.getState().isAnnotationState()) {
//            if (Props.getFlavorModel().equals(Props.Flavor.Model.Rs)) {
//                settingsMenuView.setOffsetRight(getResources().getDimensionPixelOffset(R.dimen.settings_menu_annotation_offset_right));
//            }
//        } else {
//            if (Props.getFlavorModel().equals(Props.Flavor.Model.Rs)) {
//                settingsMenuView.setOffsetRight(0);
//            }
//        }
    }

    private void initPluginsToolbarMenuView() {
        if (pluginsToolbarMenuView != null) {
            return;
        }
        pluginsToolbarMenuViewViewStub.inflate();
        pluginsToolbarMenuView = findViewById(R.id.plugins_menu);
        pluginsToolbarMenuView.setPluginsListener(this);
        pluginsToolbarMenuView.setVisibility(GONE);
        initOptionsMenuView();
    }

    private void initPenMenuView() {
        if (penMenuView != null) {
            return;
        }
        penMenuViewViewStub.inflate();
        penMenuView = findViewById(R.id.pen_menu);
        penMenuView.setColor(stylusPenProp.getColor());
        penMenuView.setSize(stylusPenProp.getSize());
        penMenuView.setOnChangeListener((device, color, size) -> {
            log("onSelectPenProp: device=" + device + ", color=" + color + ", size=" + size);
            final PenProperty penProp = device == Device.FINGER ? fingerPenProp : stylusPenProp;
            penProp.setColor(color);
            penProp.setSize(size);
            updatePenUi(penProp);
            whiteboard.queueInput(InputEvent.createInputChangeAction(device, Whiteboard.Input.PEN));

            if (floatingBarView != null) {
                floatingBarView.updatePenUi(penProp);
                floatingBarView.setPenMenuProp(penProp);
            }
        });
        penMenuView.setOnTouchListener(toggleInputTouchListener);
        penMenuView.setVisibility(GONE);
    }

    private void initHighLighterMenuView() {
        if (highlighterMenuView != null) {
            return;
        }
        highLighterMenuViewViewStub.inflate();
        highlighterMenuView = findViewById(R.id.highlighter_menu);
        highlighterMenuView.setColor(fingerHighlighterProp.getColor());
        highlighterMenuView.setSize(fingerHighlighterProp.getSize());
        highlighterMenuView.setOnChangeListener((device, color, size) -> {
            log("onSelectHighlighterProp: device=" + device + ", color=" + color + ", size=" + size);
            final HighlighterProperty highlighterProp = device == Device.FINGER ? fingerHighlighterProp : stylusHighlighterProp;
            highlighterProp.setColor(color);
            highlighterProp.setSize(size);
            updateHighlighterUi(highlighterProp);
            whiteboard.queueInput(InputEvent.createInputChangeAction(device, Whiteboard.Input.HIGHLIGHTER));
            if (floatingBarView != null) {
                floatingBarView.updateHighlighterUi(highlighterProp);
                floatingBarView.setHighlighterMenuProp(highlighterProp);
            }
        });
        highlighterMenuView.setOnTouchListener(toggleInputTouchListener);
        highlighterMenuView.setVisibility(GONE);
    }

    private void initAutoShapeMenuView() {
        if (autoshapeMenuView != null) {
            return;
        }
        autoShapeMenuViewViewStub.inflate();
        autoshapeMenuView = findViewById(R.id.autoshape_menu);
        autoshapeMenuView.setVisibility(GONE);
        autoshapeMenuView.setType(autoshapeProp.getType());
        autoshapeMenuView.setColor(autoshapeProp.getColor());
        autoshapeMenuView.setOnChangeListener(new AutoshapeMenuView.OnChangeListener() {
            @Override
            public void onSelectAutoshapeColor(int pointer, AutoshapeProperty.Color color) {
                autoshapeProp.setColor(color);
            }

            @Override
            public void onSelectAutoshapeType(int pointer, AutoshapeProperty.Type type) {
                autoshapeProp.setType(type);

                if (Props.getFlavorModel().equals(Props.Flavor.Model.Rs) || Props.getFlavorModel().equals(Props.Flavor.Model.Oem)) {
                    inputAutoshape.setImageResource(autoshapeProp.getTypeDrawableRes());
                }
            }

            @Override
            public void onSetAutoshapeFillEnabled(int pointer, boolean fillEnabled) {
                autoshapeProp.setFill(fillEnabled);
            }
        });
        autoshapeMenuView.setOnTouchListener(toggleInputTouchListener);
    }

    private void initWordMenuView() {
        if (wordMenuView != null) {
            return;
        }
        wordMenuViewViewStub.inflate();
        wordMenuView = findViewById(R.id.word_menu);
        wordMenuView.setVisibility(GONE);
        wordMenuView.setSize(wordProp.getSize());
        wordMenuView.setColor(wordProp.getColor());
        wordMenuView.setOnChangeListener(new WordMenuView.OnChangeListener() {
            @Override
            public void onSelectWordColor(int pointer, WordProperty.TextColor color) {
                log("onSelectWordColor: color" + color);
                wordProp.setColor(color);

                if (Props.getFlavorModel().equals(Props.Flavor.Model.Rs)) {
                    updateWordActionColor();
                }
            }

            @Override
            public void onSelectWordSize(int pointer, float size) {
                wordProp.setSize(size);
            }
        });
        wordMenuView.setOnTouchListener(toggleInputTouchListener);
    }

    private void initPageView() {
        if (pageMenuView != null) {
            return;
        }
        pageMenuViewViewStub.inflate();
        pageMenuView = findViewById(R.id.page_menu);
        pageMenuView.setVisibility(GONE);
        pageMenuView.setColor(pageProp.getColor());
        pageMenuView.setPattern(pageProp.getPattern());
        pageMenuView.setOnChangeListener((color, pattern) -> {
            pageProp.setColor(color);
            pageProp.setPattern(pattern);
            addNewPage();
        });
        pageMenuView.setOnImportClickListener(() -> {
            Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
            intent.setType("image/*");
//                    intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[] {"image/jpeg", "image/png", "image/bmp", "image/gif"});
            intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[]{"image/jpeg", "image/png", "image/bmp"});
            if (intent.resolveActivity(getPackageManager()) != null) {
                startActivityForResult(intent, REQUEST_GET_CUSTOM_BACKGROUND);
            }
        });
    }

    private void initImageToolbarMenuView() {
        if (imageToolbarMenuView != null) {
            return;
        }
        imageToolBarMenuViewViewStub.inflate();
        imageToolbarMenuView = findViewById(R.id.image_toolbar_menu);
        imageToolbarMenuView.setVisibility(View.GONE);
        imageToolbarMenuView.setImageToolbarListener(this);
        imageToolbarMenuView.setOnTouchListener(toggleInputTouchListener);
    }

    private void initWhiteboardDialogView() {
        if (dialog != null) {
            return;
        }
        whiteboardDialogViewStub.inflate();
        dialog = findViewById(R.id.dialog);
    }

    private void initNavigatorView() {
        if (navigatorView != null) {
            return;
        }
        navigatorViewViewStub.inflate();
        navigatorView = findViewById(R.id.navigator_view);
        navigatorView.setListener(this);
        navigatorView.setFileHandler(fileHandler);
    }

    private void initSearchImageView() {
        if (searchImageView != null) {
            return;
        }
        searchImageViewViewStub.inflate();
        searchImageView = findViewById(R.id.search_image_view);
        searchImageView.setVisibility(View.GONE);
        searchImageView.setSearchViewListener(this);
        searchImageView.setImagePreview(findViewById(R.id.image_preview));
    }

    private void initYoutubeSearchView() {
        if (youtubeSearchView != null) {
            return;
        }
        youtubeSearchViewStub.inflate();
        youtubeSearchView = findViewById(R.id.youtube_search_view);
        youtubeSearchView.setVisibility(View.GONE);
    }

    private void initJsonLoadBlockingImageView() {
        if (jsonBlockingView != null) {
            return;
        }
        jsonLoadBlockingImageViewViewStub.inflate();
        jsonBlockingView = findViewById(R.id.json_blocking_view);
    }

    private void initJsonAlertView() {
        if (jsonAlertView != null) {
            return;
        }
        jsonAlertViewViewStub.inflate();
        jsonAlertView = findViewById(R.id.json_alert_view);
    }

    private void initEraserMenuView() {
        if (eraserMenuView != null) {
            return;
        }
        eraserMenuViewViewStub.inflate();
        eraserMenuView = findViewById(R.id.eraser_menu);
        eraserMenuView.setOnChangeListener(new EraserMenuView.OnChangeListener() {
            @Override
            public void onSelectEeaserProp(Device device, View v) {
                log("on select eraser prop QQ: d: " + device);
                setDeviceInput(device, v);
                whiteboard.resetEraserPen();
                if (v.getId() == R.id.eraser_partial) {
                    whiteboard.queueInput(InputEvent.createInputChangeAction(device, Whiteboard.Input.PARTIAL_ERASER));
                } else if (v.getId() == R.id.eraser_object) {
                    whiteboard.queueInput(InputEvent.createInputChangeAction(device, Whiteboard.Input.OBJECT_ERASER));
                }
                if (FastDraw.isSupportedCanvasFastDrawEraser()) {
                    if (v.getId() == R.id.eraser_partial) {
                        whiteboard.renderFastDrawEraserCached();
                    }
                }
            }
        });
    }

    private void setAppMode(boolean isAnnotationMode) {
        final WhiteboardState state;
        if (isAnnotationMode) {
            cancelSearchTask();
            state = annotationState;
            setUiForAnnotationMode(true);

            if (Props.getFlavorModel().equals(Props.Flavor.Model.Rs)) {
                setHoldOnSourceFlag(true);
            }
        } else {
            // if display control is enabled, toggle it
            if (toggleControl != null && toggleControl.isSelected()) {
                toggleControl.callOnClick();
            }

            state = states.get(stateIndex);
            setUiForAnnotationMode(false);

            if (Props.getFlavorModel().equals(Props.Flavor.Model.Rs)) {
                setHoldOnSourceFlag(false);
            }
        }

        state.clearSelected();
        clearTextBoxAndToggleKeyboard();
        whiteboard.queueInput(InputEvent.createSetStateAction(state));

        // notify floatbar of mode change
        BroadcastHelper.sendModeSwitch(MainActivity.this, isAnnotationMode);

        hideMenus();
        updatePageNumber(state);

        updateInputUi(state.isAnnotationState());
        setInputProps(state.isAnnotationState());
        if (frontSurfaceView != null) {
            frontSurfaceView.setVisibility(isAnnotationMode ? GONE : View.VISIBLE);
        }
    }

    @SuppressLint("ClickableViewAccessibility")
    private final View.OnTouchListener toggleInputTouchListener = (v, event) -> {
        final int action = event.getActionMasked();
        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP) {
            Device device = TouchUtils.getEventDevice(this, event.getActionIndex(), event);
            if (device == Device.PALM) {
                device = Device.FINGER;
            }

            setDeviceInput(device, v);

            // todo : check setHexagonPalette, maybe not implement yet
//            @ColorInt int hexPenColor = (whiteboard.getState().isAnnotationState() ? annotationPenHexColor : whiteboardPenHexColor);
//            @ColorInt int hexHighlighterColor = (whiteboard.getState().isAnnotationState() ? annotationHighlighterHexColor : whiteboardHighlighterHexColor);
//            if(penMenuView != null)
//                penMenuView.setHexagonPalette(hexPenColor);
//            if(highlighterMenuView!=null)
//                highlighterMenuView.setHexagonPalette(hexHighlighterColor);

            switch (device) {
                case FINGER: {
                    updatePenUi(fingerPenProp);
                    updateHighlighterUi(fingerHighlighterProp);
                    if (penMenuView != null) {
                        penMenuView.setSize(fingerPenProp.getSize());
                        penMenuView.setColor(fingerPenProp.getColor());
                    }
                    if (highlighterMenuView != null) {
                        highlighterMenuView.setSize(fingerHighlighterProp.getSize());
                        highlighterMenuView.setColor(fingerHighlighterProp.getColor());
                    }
                    if (floatingBarView != null) {
                        floatingBarView.updatePenUi(fingerPenProp);
                        floatingBarView.updateHighlighterUi(fingerHighlighterProp);

                        floatingBarView.setPenMenuProp(fingerPenProp);
                        floatingBarView.setHighlighterMenuProp(fingerHighlighterProp);
                    }
                    break;
                }
                case STYLUS: {
                    updatePenUi(stylusPenProp);
                    updateHighlighterUi(stylusHighlighterProp);
                    if (penMenuView != null) {
                        penMenuView.setSize(stylusPenProp.getSize());
                        penMenuView.setColor(stylusPenProp.getColor());
                    }
                    if (highlighterMenuView != null) {
                        highlighterMenuView.setSize(stylusHighlighterProp.getSize());
                        highlighterMenuView.setColor(stylusHighlighterProp.getColor());
                    }
                    if (floatingBarView != null) {
                        floatingBarView.updatePenUi(stylusPenProp);
                        floatingBarView.updateHighlighterUi(stylusHighlighterProp);

                        floatingBarView.setPenMenuProp(stylusPenProp);
                        floatingBarView.setHighlighterMenuProp(stylusHighlighterProp);
                    }
                    break;
                }
            }
        }
        return false;
    };

    private final View.OnClickListener buildInfoOnClickListener = new View.OnClickListener() {
        private static final long TIME_PERIOD = 2000L; // ms
        private static final int CLICK_COUNT = 5;
        private static final long FADE_DELAY = 4000L;
        private static final long FADE_DURATION = 1000L;

        private long start;
        private int count;
        private ViewPropertyAnimator animator;

        @Override
        public void onClick(View v) {
            if (count == 0) {
                // initial click
                start = System.currentTimeMillis();
                count++;
            } else if (System.currentTimeMillis() - start < TIME_PERIOD) {
                // click is within time period, count it
                count++;
            } else {
                // time has expired, start over
                start = System.currentTimeMillis();
                count = 1;
            }

            if (count >= CLICK_COUNT) {
                // toggle build info visibility and reset count
                count = 0;

                if (animator != null) {
                    animator.cancel();
                }

                buildInfo.setVisibility(View.VISIBLE);
                buildInfo.setAlpha(1f);

                animator = buildInfo.animate()
                        .alpha(0f)
                        .setStartDelay(FADE_DELAY)
                        .setDuration(FADE_DURATION)
                        .setListener(listener);
            }
        }

        private final AnimatorListenerAdapter listener = new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                buildInfo.setVisibility(View.GONE);
                animator = null;
            }
        };
    };

    private View.OnClickListener renderTestClickListener = new View.OnClickListener() {
        private static final long TIME_PERIOD = 2000L; // ms
        private static final long REFRESH_TIME_PERIOD = 1000L; // ms
        private final int COUNT = 5;
        private long start = 0L;
        private int clickCount = 0;
        private View renderDebugView;
        private @ColorInt
        int penRed;
        private @ColorInt
        int penYellow;
        private long lastChange = 0L;

        @Override
        public void onClick(View v) {
            if (renderDebugView == null) {
                renderDebugView = findViewById(R.id.render_debug_view);
                penRed = ContextCompat.getColor(getApplicationContext(), R.color.pen_red);
                penYellow = ContextCompat.getColor(getApplicationContext(), R.color.pen_yellow);
            }

            long now = System.currentTimeMillis();
            if (now - start < TIME_PERIOD) {
                clickCount++;
            }
            if (clickCount >= COUNT) {
                clickCount = 0;
                renderDebugView.setVisibility(View.VISIBLE);
                renderDebugView.setSelected(true);
                thread.setDebugListener(new RenderThread.RendererDebugListener() {
                    @Override
                    public void onRendererStatus(long time) {
                        runOnUiThread(() -> {
                            if (renderDebugView.getVisibility() == View.VISIBLE) {
                                if (time - lastChange >= REFRESH_TIME_PERIOD) {
                                    renderDebugView.setSelected(!renderDebugView.isSelected());
                                    renderDebugView.setBackgroundColor(renderDebugView.isSelected() ? penRed : penYellow);
                                    lastChange = time;
                                }
                            }
                        });
                    }

                    @Override
                    public void onThreadStop() {
                        if (renderDebugView != null) {
                            renderDebugView.setVisibility(View.INVISIBLE);
                        }
                    }
                });
            }
            start = now;
        }
    };

    private final TextWatcher wordDelegateTextWatcher = new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            if (wordDelegate.getTextWatcherDisable()) {
                return;
            }

            if (!wordDelegate.getEdited()) {
                wordDelegate.setMinWidth((int) wordDelegate.getMinWidthAfterEdited());
                wordDelegate.setEdited(true);
            }
        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            // do nothing
        }

        @Override
        public void afterTextChanged(Editable s) {
            if (wordDelegate.getTextWatcherDisable()) {
                return;
            }

            if (!wordDelegate.getTextToTextAreaDisable()) {

                wordDelegate.measure(0, 0);

                float totalDegree = wordDelegate.getRotation();

                if (totalDegree % 360.0f != 0.0f) {

                    // Use word.getMeasureWidth()/.getMeasureHeight() to get the changed width/height because word.getWidth()/.getHeight()
                    // is only changed after afterTextChanged().
                    float boxCenterX = wordDelegate.getBoundX() + wordDelegate.getBoundW() / 2.0f;
                    float boxCenterY = wordDelegate.getBoundY() + wordDelegate.getBoundH() / 2.0f;
                    float centerOffsetX = (wordDelegate.getX() + wordDelegate.getMeasuredWidth() / 2.0f) - boxCenterX;
                    float centerOffsetY = (wordDelegate.getY() + wordDelegate.getMeasuredHeight() / 2.0f) - boxCenterY;

//                    Matrix mat = new Matrix();
                    if (mat == null) {
                        mat = new Matrix();
                    }
                    mat.reset();
                    mat.setRotate(totalDegree, .0f, .0f);
                    float[] pts = {centerOffsetX, centerOffsetY};
                    mat.mapPoints(pts);

                    float newCenterX = boxCenterX + pts[0];
                    float newCenterY = boxCenterY + pts[1];
                    float newTextX = newCenterX - wordDelegate.getMeasuredWidth() / 2.0f;
                    float newTextY = newCenterY - wordDelegate.getMeasuredHeight() / 2.0f;

                    wordDelegate.setX(newTextX);
                    wordDelegate.setY(newTextY);

                    if (newTextX != wordDelegate.getX() || newTextY != wordDelegate.getY()) {
                        wordDelegate.modifiedSetTranslate(newTextX - wordDelegate.getX(), newTextY - wordDelegate.getY());
                    }
                    float newBoundW = wordDelegate.getBoundW() + centerOffsetX * 2;
                    float newBoundH = wordDelegate.getBoundH() + centerOffsetY * 2;
                    float newBoundX = newCenterX - newBoundW / 2.0f;
                    float newBoundY = newCenterY - newBoundH / 2.0f;
                    wordDelegate.setBound(newBoundX, newBoundY, newBoundW, newBoundH);
                }

                wordDelegate.measure(0, 0);
                ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) wordDelegate.getLayoutParams();
                layoutParams.height = wordDelegate.getMeasuredHeight();
                wordDelegate.setLayoutParams(layoutParams);

                whiteboard.queueInput(InputEvent.createActiveWordTextChangeAction(s.toString(), wordDelegate.getX(), wordDelegate.getY(),
                        wordDelegate.getMeasuredWidth(), wordDelegate.getMeasuredHeight(), wordDelegate.getCurrentKeyCode(),
                        Math.max(wordDelegate.getSelectionStart(), wordDelegate.getSelectionEnd())));
            }
            wordDelegate.setCurrentKeyCode(ModifiedEditTextForSkia.KEYCODE_INVALID);
        }
    };

    private void updatePageNumber(WhiteboardState state) {
        Whiteboard.isscale = true;
        Whiteboard.first = true;
        if (pageNumber != null) {
            if (state == null || state.isAnnotationState()) {
                pageNumber.setVisibility(View.GONE);
            } else {
                pageNumber.setVisibility(View.VISIBLE);
                pageNumber.setSelected(!state.isPageColorDark());
                pageNumber.setText(getString(R.string.page_number, stateIndex + 1, states.size()));
            }
        }
    }

    private void toggleInput(View inputView) {
        // if display control is enabled, toggle it
        if (toggleControl != null && toggleControl.isSelected()) {
            toggleControl.callOnClick();
        }

        if (inputView != null) {
            inputView.setSelected(true);
        }

        for (View v : inputGroup) {
            if (v != inputView) {
                v.setSelected(false);
            }
        }
    }

    private View getCurrentInput() {
        for (View input : inputGroup) {
            if (input.isSelected()) {
                return input;
            }
        }
        return null;
    }

    private void setDeviceInput(Device device, View button) {
        log("setPointerInput: device=" + device);
        Whiteboard.Input input = null;
        switch (button.getId()) {
            case R.id.add_autoshape:
            case R.id.autoshape_menu: {
                input = Whiteboard.Input.AUTOSHAPE;
                break;
            }
            case R.id.add_text:
            case R.id.word_menu: {
                input = Whiteboard.Input.TEXT;
                break;
            }
            case R.id.input_pen:
            case R.id.pen_menu: {
                input = Whiteboard.Input.PEN;
                break;
            }
            case R.id.input_highlighter:
            case R.id.highlighter_menu: {
                input = Whiteboard.Input.HIGHLIGHTER;
                break;
            }
            case R.id.input_select: {
                input = Whiteboard.Input.SELECT;
                break;
            }
            case R.id.input_eraser: {
                if (eraserMenuView.getCurMode() == EraserMenuView.EraserMode.OBJECT) {
                    input = Whiteboard.Input.OBJECT_ERASER;
                } else {
                    input = Whiteboard.Input.PARTIAL_ERASER;
                }
                break;
            }
            case R.id.eraser_object: {
                input = Whiteboard.Input.OBJECT_ERASER;
                break;
            }
            case R.id.eraser_partial: {
                input = Whiteboard.Input.PARTIAL_ERASER;
                break;
            }
            case R.id.move_canvas: {
                input = Whiteboard.Input.MOVE_CANVAS;
                break;
            }
        }
        if (button.getId() == R.id.input_highlighter) {
            FastDraw.isHighliter = true;
        } else {
            FastDraw.isHighliter = false;
        }

        log("- input=" + input);
        if (input != null) {
            whiteboard.queueInput(InputEvent.createInputChangeAction(device, input));
//            if (Props.getFlavorModel().equals(Props.Flavor.Model.Oem) && input == Whiteboard.Input.MOVE_CANVAS) {
//                whiteboard.queueInput(InputEvent.createInputChangeAction(Device.FINGER, input));
//                whiteboard.queueInput(InputEvent.createInputChangeAction(Device.STYLUS, input));
//            } else {
//                whiteboard.queueInput(InputEvent.createInputChangeAction(device, input));
//            }
        }
    }

    private void clearSelection() {
        whiteboard.queueInput(InputEvent.createAction(InputEvent.Action.CLEAR_SELECTION));
    }

    private void clearTextBoxAndToggleKeyboard() {
        whiteboard.queueInput(InputEvent.createAction(InputEvent.Action.CLEAR_TEXTBOX_CONTROL_KEYBOARD));

        InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
        if (imm == null) {
            return;
        }

        View view = getCurrentFocus();
        if (view != null) {
            imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
        }

        // recheck if word delegate is closed
        hideWordDelegate();
    }

    private void setInputProps(boolean isAnnotationMode) {
        if (isAnnotationMode) {
            whiteboard.setPenProperties(annotationFingerPenProp, annotationStylusPenProp);
            whiteboard.setHighlighterProperties(annotationFingerHighlighterProp, annotationStylusHighlighterProp);
        } else {
            whiteboard.setPenProperties(whiteboardFingerPenProp, whiteboardStylusPenProp);
            whiteboard.setHighlighterProperties(whiteboardFingerHighlighterProp, whiteboardStylusHighlighterProp);
        }
    }

    /**
     * Updates input UI.
     */
    private void updateInputUi(boolean isAnnotationMode) {
        if (isAnnotationMode) {
            fingerPenProp = annotationFingerPenProp;
            stylusPenProp = annotationStylusPenProp;
            fingerHighlighterProp = annotationFingerHighlighterProp;
            stylusHighlighterProp = annotationStylusHighlighterProp;
        } else {
            fingerPenProp = whiteboardFingerPenProp;
            stylusPenProp = whiteboardStylusPenProp;
            fingerHighlighterProp = whiteboardFingerHighlighterProp;
            stylusHighlighterProp = whiteboardStylusHighlighterProp;
        }

        updatePenUi(fingerPenProp);
        updateHighlighterUi(fingerHighlighterProp);
        if (floatingBarView != null) {
            floatingBarView.updatePenUi(fingerPenProp);
            floatingBarView.updateHighlighterUi(fingerHighlighterProp);
        }

        if (penMenuView != null) {
            penMenuView.setColor(fingerPenProp.getColor());
            penMenuView.setSize(fingerPenProp.getSize());
        }
        if (floatingBarView != null) {
            floatingBarView.setPenMenuViewColor(fingerPenProp.getColor());
            floatingBarView.setPenMenuViewSize(fingerPenProp.getSize());
        }
        if (highlighterMenuView != null) {
            highlighterMenuView.setColor(fingerHighlighterProp.getColor());
            highlighterMenuView.setSize(fingerHighlighterProp.getSize());
        }
        if (floatingBarView != null) {
            floatingBarView.setHighlighterMenuViewColor(fingerHighlighterProp.getColor());
            floatingBarView.setHighlighterMenuViewSize(fingerHighlighterProp.getSize());
        }

        if (Props.getFlavorModel().equals(Props.Flavor.Model.Rs) || Props.getFlavorModel().equals(Props.Flavor.Model.Oem)) {
            inputAutoshape.setImageResource(autoshapeProp.getTypeDrawableRes());
            // disable word color change after UI update
//            updateWordActionColor();
        }
    }

    private void updateWordActionColor() {
        if (inputText != null) {
            if (wordProp.getColor() == WordProperty.TextColor.WHITE) {
                inputText.setImageResource(R.drawable.ic_import_text);
            } else {
                Drawable drawable = ContextCompat.getDrawable(this, R.drawable.ic_import_text);
                if (drawable != null) {
                    DrawableCompat.setTint(drawable,
                            ContextCompat.getColor(this, wordProp.getColorRes()));
                    inputText.setImageDrawable(drawable);
                }
            }
        }
    }

    /**
     * Updates the penProperty button.
     */
    private void updatePenUi(PenProperty penProperty) {
        @ColorInt int white = ContextCompat.getColor(this, R.color.pen_white);
        if (penProperty.getColor() == white) {
            penStroke.setImageResource(penProperty.getOutlinedStrokeRes());
        } else {
            Drawable stroke = ContextCompat.getDrawable(this, penProperty.getStrokeRes());
            if (stroke != null) {
                DrawableCompat.setTint(stroke, penProperty.getColor());
                penStroke.setImageDrawable(stroke);
            }
        }
    }

    /**
     * Updates the highlighterProperty button.
     */
    private void updateHighlighterUi(HighlighterProperty highlighterProperty) {
        @ColorInt int white = ContextCompat.getColor(this, R.color.highlight_white);
        if (highlighterProperty.getColor() == white) {
            highlighterStroke.setImageResource(highlighterProperty.getOutlinedStrokeRes());
        } else {
            Drawable stroke = ContextCompat.getDrawable(this, highlighterProperty.getStrokeRes());
            if (stroke != null) {
                final int color = highlighterProperty.getColor();
                DrawableCompat.setTint(stroke, color | 0xFF000000); // remove transparency
                highlighterStroke.setImageDrawable(stroke);
            }
        }
    }

    private void hideMenus() {
        if (penMenuView != null) {
            penMenuView.setVisibility(View.GONE);
            penMenuView.hideHexagonPalette();
        }
        if (highlighterMenuView != null) {
            highlighterMenuView.setVisibility(View.GONE);
            highlighterMenuView.hideHexagonPalette();
        }
        if (autoshapeMenuView != null) {
            autoshapeMenuView.setVisibility(View.GONE);
        }
        if (wordMenuView != null) {
            wordMenuView.setVisibility(View.GONE);
        }
        if (eraserMenuView != null) {
            eraserMenuView.setVisibility(View.GONE);
        }
        if (pageMenuView != null) {
            pageMenuView.setVisibility(View.GONE);
        }
        if (imageToolbarMenuView != null) {
            imageToolbarMenuView.setVisibility(View.GONE);
        }
        if (searchImageView != null) {
            searchImageView.setVisibility(View.GONE);
            if (searchThumbnailsTask != null) {
                if (browserCrawler != null) {
                    browserCrawler.abortOkHttpRequest();
                }
                searchThumbnailsTask.cancel(true);
            }
        }
        if (youtubeSearchView != null) {
            youtubeSearchView.setVisibility(GONE);
            youtubeSearchView.toggleWebView(youtubeSearchView.getVisibility() == View.VISIBLE);
        }
        if (floatingBarView != null) {
            floatingBarView.hideMenus();
        }
        if (settingsMenuView != null) {
            settingsMenuView.hide();
        }
        if (paste != null) {
            paste.setVisibility(View.GONE);
        }
        if (eraserAreaView != null) {
            eraserAreaView.setVisibility(View.GONE);
        }
        if (pluginsToolbarMenuView != null) {
            pluginsToolbarMenuView.setVisibility(GONE);
        }
        if (navigatorView != null) {
            navigatorView.setVisibility(GONE);
        }
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        log("surfaceCreated");
        surface.setWillNotDraw(false);
        if (thread == null || thread.getState() == Thread.State.TERMINATED) {
            thread = new RenderThread(whiteboard, holder, fastDraw);
            thread.setRunning(true);
            thread.start();
            if (isFirstStart) {
                isFirstStart = false;
                thread.setPaused(true);
            }
        } else if (thread.getState() == Thread.State.NEW) {
            thread.setRunning(true);
            thread.start();
            if (isFirstStart) {
                isFirstStart = false;
                thread.setPaused(true);
            }
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        log("surfaceChanged: width=" + width + ", height=" + height);
        whiteboard.queueInput(InputEvent.createSetSizeAction(width, height));
        if (thread != null) {
            handler.post(() -> {
                log("surfaceChanged : thread.setPaused false : time :" + System.currentTimeMillis());
                thread.setPaused(false);
            });
            if (postSurfaceChangedRunnable != null) {
                handler.post(postSurfaceChangedRunnable);
                postSurfaceChangedRunnable = null;
            }
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        log("surfaceDestroyed");
        boolean retry = true;
        thread.setRunning(false);
        while (retry) {
            try {
                thread.join();
                retry = false;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        thread = null;
    }

    private void showPasteAction(float x, float y) {
        if (paste != null) {
            ((PointF) paste.getTag()).set(x, y); // store the original coordinate

            // offset the button so it's not hidden under a user's finger
            x -= paste.getWidth();
            y -= paste.getHeight();
            if (x < 0) {
                x = 0;
            }
            if (y < 0) {
                y = 0;
            }

            // show paste button
            paste.setX(x);
            paste.setY(y);
            paste.setVisibility(View.VISIBLE);

            clearSelection();
        }
    }

    private void showFloatingBarAction(float x, float y) {
        log("floatingBarPosition:" + x + "," + y);
//        ((PointF) floatingBarView.getTag()).set(x, y); // store the original coordinate

        // offset the button so it's not hidden under a user's finger
//        x -= penMenuView.getWidth()/2;
        x -= floatingBarInsetLeft;
//        y -= penMenuView.getHeight();
        y -= floatingBarInsetTop;

        final int width = surface.getWidth();
        final int height = surface.getHeight() - floatingBarInsetBottom;

//        x -= floatingBarView.getWidth();
//        y -= floatingBarView.getHeight();
        if (x < floatingBarInsetLeft / 2) {
            x = floatingBarInsetLeft / 2.0f;
        } else if (x > width - floatingBarView.getWidth()) {
            x = width - floatingBarView.getWidth();
        }
        if (y < floatingBarInsetTop / 2) {
            y = floatingBarInsetTop / 2.0f;
        } else if (y > height - floatingBarView.getHeight()) {
            y = height - floatingBarView.getHeight();
        }

        //todo : adjust some case of showing floatingbar
        if (penMenuView != null) {
            log("long press for floatingBar,floatingBarWidth:" + penMenuView.getWidth());
        }
        floatingBarView.setX(x);
        floatingBarView.setY(y);
        floatingBarView.setVisibility(View.VISIBLE);


        floatingBarView.invalidate();


        clearSelection();
    }

    @Override
    public void onStateClick(long stateId) {
        for (int i = 0, size = states.size(); i < size; i++) {
            final WhiteboardState state = states.get(i);
            if (state.getId() == stateId) {
                stateIndex = i;
                whiteboard.queueInput(InputEvent.createSetStateAction(state));
                navigatorView.hide();

                updatePageNumber(state);
                break;
            }
        }
    }

    @Override
    public void onStatesDeleted(List<Long> deleted) {
        final WhiteboardState currentState = states.get(stateIndex);
        final long currentStateId = currentState.getId();

        List<Integer> indexes = new ArrayList<>();
        int beforeDeletedSize = states.size();

        for (long id : deleted) {
            for (int i = 0, size = states.size(); i < size; i++) {
                WhiteboardState state = states.get(i);
                if (state.getId() == id) {
                    fileHandler.sendDeleteImageMessage(state.getPreviewFile());
                    state.recycle();

                    states.remove(i);

                    if (state.getId() == currentStateId) {
                        stateIndex--;
                    }

                    indexes.add(i);

                    break;
                }
            }
        }

        Collections.sort(indexes);

        jsonHandler.sendDeleteJsonFileMessage(indexes, beforeDeletedSize);
        mSettings.setReloadWhiteboardJsonFileSize(states.size());

        if (states.isEmpty()) {
            stateIndex = 0;

            final WhiteboardState state = new WhiteboardState(pageProp.getColor(),
                    pageProp.getPattern(), pageProp.getCustomBackground(),
                    fileHelper.generateFileName(false), false);
            states.add(state);
            navigatorView.hide();
        } else {
            if (stateIndex < 0) {
                stateIndex = 0;
            } else if (stateIndex >= states.size()) {
                stateIndex = states.size() - 1;
            }
        }
        final WhiteboardState state = states.get(stateIndex);
        if (state != currentState) {
            whiteboard.queueInput(InputEvent.createSetStateAction(state));
        }
        updatePageNumber(state);
    }

    @Override
    public void onCopyStates(List<Long> ids) {
        List<Integer> copiedIndexes = new ArrayList<>();
        int beforeCopiedSize = states.size();

        for (long id : ids) {
            if (states.size() >= maxNumWhiteboardStates) {
                break;
            }

            for (int i = 0, size = states.size(); i < size; i++) {
                final WhiteboardState state = states.get(i);
                if (state.getId() == id) {
                    states.add(state.copy(this, fileHandler));
                    copiedIndexes.add(i);
                    break;
                }
            }
        }

        jsonHandler.sendCopyJsonFileMessage(copiedIndexes, beforeCopiedSize);
        mSettings.setReloadWhiteboardJsonFileSize(states.size());

        // not ideal: pass states to navigatorView after a slight delay to allow for
        // current state's preview to update
        navigatorView.setStatesDelayed(states, stateIndex, 2000);
        updatePageNumber(states.get(stateIndex));
    }

    @Override
    public void onClickVisualizer(View v) {
        log("onClickVisualizer");
        whiteboard.clearWhiteBoard(true);
        final Intent intent = new Intent();
        intent.setClassName(PluginsToolbarMenuView.VISUALIZER_PACKAGE_NAME, PluginsToolbarMenuView.VISUALIZER_CLASS_NAME);
        startActivity(intent);
    }

    @Override
    public void onClickScreenRecorder(View v) {
        log("onClickScreenRecorder");
        final Intent intent = new Intent();
        intent.setClassName(PluginsToolbarMenuView.SCREEN_RECORDER_PACKAGE_NAME, PluginsToolbarMenuView.SCREEN_RECORDER_CLASS_NAME);
        startActivity(intent);
    }

    @Override
    public void onClickSplitMode(View v) {
        log("onClickSplitMode");
        final Intent splitModeIntent = new Intent();
        splitModeIntent.setClassName(PluginsToolbarMenuView.SPLIT_MODE_PACKAGE_NAME, PluginsToolbarMenuView.SPLIT_MODE_CLASS_NAME);
        if (clearSplitMenu) {
            splitModeIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
            clearSplitMenu = false;
        }
        startActivity(splitModeIntent);//, REQUEST_GET_WEB_IMAGE);
        overridePendingTransition(0, 0);

        setExitSplitMenu(false);
    }

    @Override
    public void onEraserReadyToDraw(Whiteboard.Input input) {
        thread.setPaused(true);
        if (Props.isPaintHelperEnabled() && fastDraw.isDrawing()) {
            isCleanBufferRequired = true;
            handler.removeCallbacks(runStopFastDraw);
            handler.post(runStopFastDraw);
        }
        toggleInput(inputEraser);
        hideMenus();
        frontSurfaceView.setBackgroundBitmap(whiteboard.getEraserBackgroundCached());
        if (input == Whiteboard.Input.PARTIAL_ERASER) {
            frontSurfaceView.setEraserBitmap(whiteboard.getFrontSurfaceEraserScratchCached());
        }
    }

    @Override
    public void onEraserDrawing(float x, float y) {

    }

    @Override
    public void onEraserDrawOver(Whiteboard.Input input) {
        if (input == Whiteboard.Input.PARTIAL_ERASER) {
            whiteboard.doPartialEraser(frontSurfaceView.getEraserLine());
        } else {
            whiteboard.doObjectEraser(frontSurfaceView.getEraserLine());
        }
        thread.setPaused(false);
        if (WbJniCall.isLoaded() && Props.getFlavorChipset().equals(Props.Flavor.Chipset.Optoma)) {
            WbJniCall.fbClear();
        }

    }

    @Override
    public void onExitClicked() {
        exitAlertView.setVisibility(GONE);
        doFinish();
//        finish();
    }

    @Override
    public void onCancelClicked() {
//        exitWhiteboard.setVisibility(GONE);
        exitAlertView.setVisibility(GONE);
    }

    @Override
    public void onMultiTouchStart() {
        if (settingsMenuView != null)
            settingsMenuView.setVisibility(GONE);
        sendMultiTouchStartIntent();
    }

    private void sendMultiTouchStartIntent() {
        log("Try to Send MultiTouch Start Intent.");
        Intent intent = new Intent();
        intent.setClassName(MULTITOUCH_TEST_PACKAGE_NAME, MULTITOUCH_TEST_CLASS_NAME);

        final List<ResolveInfo> activities = this.getPackageManager().
                queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
        if (activities.size() > 0)
            startActivity(intent);
        else {
            log("Can't find multitouch test. abort intent.");
        }
    }

    /**
     * Touch event listener for whiteboard surface view.
     */
    private class SurfaceViewOnTouchListener implements View.OnTouchListener {
        private static final long MAX_TIME_INTERVAL_FIVE_FINGER_GESTURE = 200; // ms

        private final GestureDetector gestureDetector;

        private final float touchSlopSquare;
        private final PointF firstDown;
        private boolean isTouchSlopExceeded;

        private boolean isFiveFingerActive;
        private long firstFingerDownTime;
        private boolean isMultiTouchAllowed;

        SurfaceViewOnTouchListener(Context context) {
            isMultiTouchAllowed = true;
            firstDown = new PointF();
            final ViewConfiguration config = ViewConfiguration.get(context);
            final int touchSlop = config.getScaledTouchSlop();
            touchSlopSquare = touchSlop * touchSlop;

            gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
                @Override
                public void onLongPress(MotionEvent e) {
                    log("onLongPress");
                    log("- isTouchSlopExceeded=" + isTouchSlopExceeded + ", isInTouchGesture=" + isInTouchGesture);
                    if (isTouchSlopExceeded) {
                        return;
                    }

                    if (!whiteboard.isPasteAllowed()) {
                        return;
                    }

                    log("- Props.getPhase=" + Props.getPhase());
                    if (Props.getPhase() >= Props.Phase.THREE) {
                        if (floatingBarView != null) {
                            log("- floatingBarView");
                            isInTouchGesture = true;
                            clearTextBoxAndToggleKeyboard();
                            showFloatingBarAction(e.getX(), e.getY());
                        }
                        if (!whiteboard.isClipboardEmpty()) {
                            log("- clipboard has data");
                            isInTouchGesture = true;
                            clearTextBoxAndToggleKeyboard();
                            showPasteAction(e.getX(), e.getY());
                        }
                    } else if (!whiteboard.isClipboardEmpty()) {
                        log("- clipboard has data");
                        isInTouchGesture = true;
                        clearTextBoxAndToggleKeyboard();
                        showPasteAction(e.getX(), e.getY());
                    }

                    log("- isInTouchGesture=" + isInTouchGesture);
                    if (isInTouchGesture) {
                        cancelFastDraw();
                        whiteboard.queueInput(InputEvent.createRemoveActiveItemsAction(false));
                    }
                }
            });
        }

        private boolean isPaintHelperStartable() {
            final InputManager inputManager = InputManager.getInstance();

            if (Props.getFlavorModel().equals(Props.Flavor.Model.Rs)) {
                // for RS, allow fast draw if only pen is selected
                return FastDraw.isSupported()
                        && inputManager.getInput(Device.FINGER) == Whiteboard.Input.PEN
                        && inputManager.getInput(Device.STYLUS) == Whiteboard.Input.PEN;
            } else {
                // for all other models, allow fast draw if eraser is not selected
                return FastDraw.isSupported()
                        && inputManager.getInput(Device.FINGER) != Whiteboard.Input.OBJECT_ERASER
                        && inputManager.getInput(Device.STYLUS) != Whiteboard.Input.OBJECT_ERASER;
            }
        }

        // use this method for oem , startable if current device is NOT eraser
        private boolean isPaintHelperStartable(Device device) {
            final InputManager inputManager = InputManager.getInstance();
            boolean isEraserFastDrawOk = FastDraw.isSupportedCanvasFastDrawEraser();
            Whiteboard.Input input = inputManager.getInput(device);
            boolean isEraser = input == Whiteboard.Input.OBJECT_ERASER || input == Whiteboard.Input.PARTIAL_ERASER;

            if (isMultiTouchAllowed)
                isMultiTouchAllowed = FastDraw.isSupported()
                        && inputManager.getInput(device) != Whiteboard.Input.OBJECT_ERASER
                        && inputManager.getInput(device) != Whiteboard.Input.PARTIAL_ERASER
                        && inputManager.getInput(device) != Whiteboard.Input.SELECT;


//            return FastDraw.isSupported()
//                    && inputManager.getInput(Device.FINGER) != Whiteboard.Input.OBJECT_ERASER
//                    && inputManager.getInput(Device.STYLUS) != Whiteboard.Input.PARTIAL_ERASER
//                    && inputManager.getInput(Device.FINGER) != Whiteboard.Input.PARTIAL_ERASER
//                    && inputManager.getInput(Device.STYLUS) != Whiteboard.Input.OBJECT_ERASER;
            if (FastDraw.isSupported()) {
                if (device == Device.STYLUS || device == Device.FINGER) {
                    if ((Props.getFlavorChipset().equals(Props.Flavor.Chipset.Hisi) || Props.getFlavorChipset().equals(Props.Flavor.Chipset.Amlogic)) && Props.getFlavorModel().equals(Props.Flavor.Model.Oem)) {
                        return input == Whiteboard.Input.PEN || input == Whiteboard.Input.HIGHLIGHTER || isEraser;
                    } else {
                        return input == Whiteboard.Input.PEN || input == Whiteboard.Input.HIGHLIGHTER;
                    }
                } else if (device == Device.PALM) {
                    return Props.getFlavorModel().equals(Props.Flavor.Model.Oem) && Props.getFlavorChipset().equals(Props.Flavor.Chipset.Hisi)
                            && isEraser;
                }
            }

            return false;

        }

        private boolean isPaintHelperStartEnableNewLine(Device device) {
            if (!FastDraw.isSupported()) {
                return false;
            }

            final InputManager inputManager = InputManager.getInstance();
            final Whiteboard.Input input = inputManager.getInput(device);
            boolean isEraser = (input == Whiteboard.Input.PARTIAL_ERASER || input == Whiteboard.Input.OBJECT_ERASER);

            if (mSettings.getImplementRecognitionMode() == Settings.IMPLEMENT_RECOGNITION_ON_ONLY_PEN) {
                if (device == Device.STYLUS || device == Device.FINGER) {
                    if (Props.getFlavorChipset().equals(Props.Flavor.Chipset.Hisi)) {
                        return input == Whiteboard.Input.PEN || input == Whiteboard.Input.HIGHLIGHTER || isEraser;
                    } else {
                        return input == Whiteboard.Input.PEN;
                    }
                }
            } else if (mSettings.getImplementRecognitionMode() == Settings.IMPLEMENT_RECOGNITION_ON_PEN_OR_FINGERS) {
                if (device == Device.STYLUS || device == Device.FINGER) {
                    if (Props.getFlavorChipset().equals(Props.Flavor.Chipset.Hisi)) {
                        return input == Whiteboard.Input.PEN || input == Whiteboard.Input.HIGHLIGHTER || isEraser;
                    }
                }
            } else {
                if (device == Device.STYLUS || device == Device.FINGER) {
                    if (Props.getFlavorChipset().equals(Props.Flavor.Chipset.Hisi)) {
                        return input == Whiteboard.Input.PEN || input == Whiteboard.Input.HIGHLIGHTER || isEraser;
                    } else {
                        return input == Whiteboard.Input.PEN;
                    }
                }
            }

            return false;
        }

        private boolean exceedsTouchSlop(float x1, float y1, float x2, float y2) {
            final float deltaX = x1 - x2;
            final float deltaY = y1 - y2;
            final float distance = (deltaX * deltaX) + (deltaY * deltaY);
            return distance >= touchSlopSquare;
        }

        @SuppressLint("ClickableViewAccessibility")
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if (!isTouchAllowed(event)) {
                return false;
            }

            // check for long press
            gestureDetector.onTouchEvent(event);

            final int pointerCount = event.getPointerCount();
            final int action = event.getActionMasked();
            final int index = event.getActionIndex();
            final int pointerId = event.getPointerId(index);
            final Device device = TouchUtils.getEventDevice(MainActivity.this, pointerId, event);

////            if (device != Device.STYLUS || settings.getImplementRecognitionMode() != Settings.IMPLEMENT_RECOGNITION_ALL) {
//            if (device == Device.FINGER || (device == Device.STYLUS && settings.getImplementRecognitionMode() == Settings.IMPLEMENT_RECOGNITION_OFF)) {
//                // check for long press
//                gestureDetector.onTouchEvent(event);
//            }


            final Whiteboard.Input input = InputManager.getInstance().getInput(device);
            final boolean isEraser = input == Whiteboard.Input.PARTIAL_ERASER;

            if (pointerCount == 1 && (input == Whiteboard.Input.PARTIAL_ERASER
                    || input == Whiteboard.Input.OBJECT_ERASER || input == Whiteboard.Input.SELECT)) {
                isMultiTouchAllowed = false;
            }

            if (device == Device.PALM) {
                isMultiTouchAllowed = false;
                isFiveFingerActive = false;
            }

            if (isFiveFingerActive) {
                log("stylus touch down with five finger triggered.");
                if (pointerCount == 1)
                    isFiveFingerActive = false;
                if (device == Device.STYLUS || pointerCount > 5)
                    return false;
            }


            switch (action) {
                case MotionEvent.ACTION_DOWN: {
                    Myhandler.removeMessages(100);
                    Myhandler.removeMessages(101);
                    log("onTouch: ACTION_DOWN");

//                    final Device device = TouchUtils.getEventDevice(MainActivity.this, 0, event);
                    log("- pointerId=" + event.getPointerId(event.getActionIndex()) + ", pointerCount=" + pointerCount + ", device=" + device);

                    hideMenus();
                    if (floatingBarView != null) {
                        floatingBarView.setVisibility(View.INVISIBLE);
                    }

                    if (Props.isPaintHelperEnabled()) {
                        handler.removeCallbacks(runStopFastDraw);
                    }

                    if (eraserAreaView != null && !FastDraw.isSupportedCanvasFastDrawEraser() && !isEraser) {
                        eraserAreaView.setVisibility(View.GONE);
                    }

                    if (FastDraw.isSupportedCanvasFastDrawEraser()) {
                        if (input == Whiteboard.Input.PARTIAL_ERASER) {
                            whiteboard.renderFastDrawEraserCached();
                        }
                        // enable or disable eraser
                        fastDraw.updateEraser(device, input);
                    }

                    if (!fastDraw.isDrawing()) {
                        log("isPaintHelperStartable(" + device + ") = " + isPaintHelperStartable(device));
//                        if (Props.isPaintHelperEnabled() && isPaintHelperStartable(device) && device != Device.PALM) {
                        if (isPaintHelperStartable(device)) {
//                            final Whiteboard.Input input = InputManager.getInstance().getInput(device);
                            if (input == Whiteboard.Input.PEN || input == Whiteboard.Input.HIGHLIGHTER ||
                                    (FastDraw.isSupportedCanvasFastDrawEraser() && isEraser) || input == null) {
//                                isMultiTouchActive = true;
                                setFastDrawProps(0, event);
                                setMainThreadEraserAreaVisible(false, eraserAreaView.getRadius(), input);
                                try {
                                    fastDraw.start(event);
                                } catch (RemoteException e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    } else {
                        if (device == Device.PALM) {
                            isMultiTouchAllowed = false;
                            if (FastDraw.isSupportedCanvasFastDrawEraser() && isEraser) {
                                try {
                                    fastDraw.onTouch(event);
                                } catch (RemoteException e) {
                                    e.printStackTrace();
                                }
                            } else {
                                cancelFastDraw();
                                isCleanBufferRequired = true;
                            }
                        } else {
                            if (isPaintHelperStartable(device)) {
                                setFastDrawProps(0, event);
                                setMainThreadEraserAreaVisible(false, eraserAreaView.getRadius(), input);
//                            isMultiTouchActive = true;
                                try {
                                    fastDraw.onTouch(event);
                                } catch (RemoteException e) {
                                    e.printStackTrace();
                                }
                            } else {
                                return true;
                            }
                        }
                    }
                    whiteboard.queueInput(InputEvent.createTouchAction(MotionEvent.obtain(event)));
                    firstFingerDownTime = event.getEventTime();
                    firstDown.set(event.getX(), event.getY());

                    if (paste != null) {
                        paste.setVisibility(View.GONE);
                    }
                    isInTouchGesture = false;
                    isFiveFingerActive = false;
                    isTouchSlopExceeded = false;
                    checkDisplaySettings();
                    if (isWritingEyeProtectionEnabled) {
                        backlightManager.onTouchDown();
                    }
                    /*by zf */
                    setBottomBarButtonsEnable(false);
                    return true;
                }
                case MotionEvent.ACTION_UP:

                case MotionEvent.ACTION_CANCEL: {
                    boolean now = false;
                    if (now) {
                        FastDraw.needDraw = true;
                        setBottomBarButtonsEnable(true);
                        if(WbJniCall.isLoaded() && Props.getFlavorChipset().equals(Props.Flavor.Chipset.Optoma)) {
                            Myhandler.removeMessages(100);
                            Myhandler.removeMessages(101);
                            Myhandler.sendEmptyMessageDelayed(101, 10);
                            Myhandler.sendEmptyMessageDelayed(100, 600);
                        }

                        isFiveFingerActive = false;
                        firstFingerDownTime = Long.MAX_VALUE;
                        isTouchSlopExceeded = false;
                        if (pointerCount == 1)
                            isMultiTouchAllowed = true;
                        if (isWritingEyeProtectionEnabled) {
                            backlightManager.onTouchUp();
                        }
                        if (eraserAreaView != null) {
                            eraserAreaView.setVisibility(View.GONE);
                            setMainThreadEraserAreaVisible(false, eraserAreaView.getRadius(), null);
                        }
                        if (isInTouchGesture) {
                            isInTouchGesture = false;
                            return true;
                        }
                        if (isWritingEyeProtectionEnabled) {
                            backlightManager.onTouchUp();
                        }
                        boolean isEraserFastDrawOk = FastDraw.isSupportedCanvasFastDrawEraser()
                                && Props.getFlavorModel().equals(Props.Flavor.Model.Oem) && isEraser;
                        if (fastDraw.isDrawing() && (isMultiTouchAllowed) || isEraserFastDrawOk) {
                            try {
                                if (fastDraw.isPartialEraserActive()) {
                                    partialEraserDone = false;
                                }
                                fastDraw.onTouch(event);
                            } catch (RemoteException e) {
                                e.printStackTrace();
                            }
                        }
                        whiteboard.queueInput(InputEvent.createTouchAction(MotionEvent.obtain(event)));
                        return true;
                    }
                    log("onTouch: ACTION_UP or ACTION_CANCEL");
                    log("- pointerId=" + event.getPointerId(event.getActionIndex()) + ", pointerCount=" + pointerCount + ", device=" + TouchUtils.getEventDevice(MainActivity.this, event.getPointerId(event.getActionIndex()), event));
                    FastDraw.needDraw = true;
                    setBottomBarButtonsEnable(true);

                    isFiveFingerActive = false;
                    firstFingerDownTime = Long.MAX_VALUE;
                    isTouchSlopExceeded = false;

                    if (eraserAreaView != null) {
                        eraserAreaView.setVisibility(View.GONE);
                        setMainThreadEraserAreaVisible(false, eraserAreaView.getRadius(), null);
                    }

                    if (isInTouchGesture) {
                        isInTouchGesture = false;
                        return true;
                    }
                    /*by zf */
                    if (isWritingEyeProtectionEnabled) {
                        backlightManager.onTouchUp();
                    }

                    boolean isEraserFastDrawOk = FastDraw.isSupportedCanvasFastDrawEraser()
                            && Props.getFlavorModel().equals(Props.Flavor.Model.Oem) && isEraser;
                    if (fastDraw.isDrawing() && (isMultiTouchAllowed) || isEraserFastDrawOk) {
                        try {
                            if (fastDraw.isPartialEraserActive()) {
                                partialEraserDone = false;
                            }
                            fastDraw.onTouch(event);
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                    }
                    whiteboard.queueInput(InputEvent.createTouchAction(MotionEvent.obtain(event)));


                    if (Props.isPaintHelperEnabled()) {
                        handler.removeCallbacks(runStopFastDraw);
                        handler.postDelayed(runStopFastDraw, Props.getFlavorChipset().equals(Props.Flavor.Chipset.Optoma)? 1000 :  800);
                        Log.d("wx", "post runStopFastDraw");
                    }
                    if (pointerCount == 1)
                        isMultiTouchAllowed = true;
                    return true;
                }
                case MotionEvent.ACTION_POINTER_DOWN: {
                    log("onTouch: ACTION_POINTER_DOWN , device : " + device);

                    if (isInTouchGesture) {
                        return true;
                    }

                    if (FastDraw.isSupportedCanvasFastDrawEraser() && fastDraw.isDrawing() && isEraser) {
                        return true;
                    }

                    if (eraserAreaView != null) {
                        eraserAreaView.setVisibility(View.GONE);
                    }

                    // make pen and eraser mutually exclusive when mode is IMPLEMENT_RECOGNITION_ON_PEN_OR_FINGERS
                    if (mSettings.getImplementRecognitionMode() == Settings.IMPLEMENT_RECOGNITION_ON_PEN_OR_FINGERS) {
                        if (inputEraser.isSelected() && (input == Whiteboard.Input.PEN || input == Whiteboard.Input.HIGHLIGHTER)) {
                            return true;
                        } else if ((inputPen.isSelected() || inputHighlighter.isSelected())
                                && (input == Whiteboard.Input.PARTIAL_ERASER || input == Whiteboard.Input.OBJECT_ERASER)) {
                            return true;
                        }
                    }

                    isTouchSlopExceeded = true;

                    if (fastDraw.isDrawing()) {
                        log("- pointerCount=" + pointerCount + ", isFiveFingerActive=" + isFiveFingerActive);
//                        if(input == Whiteboard.Input.PARTIAL_ERASER
//                                || input == Whiteboard.Input.OBJECT_ERASER){
//
//                            cancelFastDraw();
//                            isCleanBufferRequired = true;
//                            isMultiTouchActive = false;
//                        }

                        if (isEraser) {
                            return true;
                        }

//                        if (!isFiveFingerActive && isPaintHelperStartable(device) && isMultiTouchAllowed) {
                        if (isPaintHelperStartable(device)) {
                            try {
                                setFastDrawProps(index, event);
                                fastDraw.onTouch(event);
                            } catch (RemoteException e) {
                                e.printStackTrace();
                            }
                        }
                    }

                    if (device == Device.PALM) {
                        cancelFastDraw();
                        isCleanBufferRequired = true;
                        isMultiTouchAllowed = false;
                    }

                    whiteboard.queueInput(InputEvent.createTouchAction(MotionEvent.obtain(event)));
                    return true;
                }
                default: {
//                    final int index = event.getActionIndex();
                    if (action == MotionEvent.ACTION_POINTER_UP) {
                        log("onTouch: ACTION_POINTER_UP - pointerId=" + pointerId + ", pointerCount=" + pointerCount + ", device=" + device);
//                        final int pointerId = event.getPointerId(index);
//                        final Device device = TouchUtils.getEventDevice(MainActivity.this, pointerId, event);
//                        log("- pointerId=" + pointerId + ", pointerCount=" + pointerCount + ", device=" + device);
//                        log("- fastDraw.isDrawing=" + fastDraw.isDrawing());
                        log("- isInTouchGesture=" + isInTouchGesture + ", isMultiTouchActive:" + isMultiTouchAllowed);
                    }

                    if (isInTouchGesture) {
                        return true;
                    }

                    // For eraser fastDraw
                    if (FastDraw.isSupportedCanvasFastDrawEraser() && fastDraw.isDrawing() && isEraser
                            && action == MotionEvent.ACTION_MOVE
                            && (pointerId != 0)) {
                        return true;
                    }

//                    if (!isMultiTouchActive && (input == Whiteboard.Input.PARTIAL_ERASER || input == Whiteboard.Input.OBJECT_ERASER  ) ){
//                        return true;
//                    }

                    if (pointerCount == 1
                            && exceedsTouchSlop(firstDown.x, firstDown.y, event.getX(), event.getY())) {
                        isTouchSlopExceeded = true;
                    }

                    if (fastDraw.isDrawing() && isPaintHelperStartable(device)) {// && isMultiTouchAllowed) {
                        try {
//                            log("fastdraw drag or pointer up.");
                            fastDraw.onTouch(event);
                        } catch (RemoteException e) {
                            log("fastdraw failed while drag.");
                            e.printStackTrace();
                        }
                    }
                    whiteboard.queueInput(InputEvent.createTouchAction(MotionEvent.obtain(event)));
                    if (eraserAreaView != null && isEraser) {
//                        eraserAreaView.updatePosition(event.getX(), event.getY());
                        if (!FastDraw.isSupportedCanvasFastDrawEraser()) {
                            eraserAreaView.updatePosition(event.getX(), event.getY());
                        }
                    }

                    return true;
                }
            }
        }

        private void setFastDrawProps(int pointerIndex, MotionEvent event) {
            final Device device = TouchUtils.getEventDevice(MainActivity.this, pointerIndex, event);
            final Whiteboard.Input input = InputManager.getInstance().getInput(device);
            //細筆筆跡書寫過後，點選移動縮放後，筆跡粗細會變粗
            float canvasRatio = whiteboard.getAppliedScale();
            if (0 == canvasRatio || Float.isNaN(canvasRatio) || Float.isInfinite(canvasRatio)) {
                canvasRatio = 1;
            }
            if (input == Whiteboard.Input.PEN) {
                final PenProperty penProp = device == Device.FINGER
                        ? fingerPenProp : stylusPenProp;
                try {
                    fastDraw.setColor(device, penProp.getColor());
                    fastDraw.setWidth(device, Math.max(penProp.getStrokeWidth() * canvasRatio, penProp.getStrokeWidth()));
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            } else if (input == Whiteboard.Input.HIGHLIGHTER) {
                final HighlighterProperty highlighterProp = device == Device.FINGER
                        ? fingerHighlighterProp : stylusHighlighterProp;
                try {
                    fastDraw.setColor(device, highlighterProp.getColor());
                    fastDraw.setWidth(device, Math.max(highlighterProp.getStrokeWidth() * canvasRatio, highlighterProp.getStrokeWidth()));
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * Returns {@code true} if touch events are allowed.
     */
    private boolean isTouchAllowed(MotionEvent event) {
//        return !isFinishing && !isDisplayControlModeEnabled;
        return !isFinishing && !isDisplayControlModeEnabled && partialEraserDone;
    }

    private final Runnable runStopFastDraw = new Runnable() {
        @Override
        public void run() {
            log("runStopFastDraw.run");
            cancelFastDraw();
        }
    };

    @Override
    public void onCurrentInputChange(Device device, Whiteboard.Input input) {
        runOnUiThread(() -> {
            if (penMenuView != null) {
                penMenuView.setProp(device == Device.FINGER ? fingerPenProp : stylusPenProp);
            }
            if (highlighterMenuView != null) {
                highlighterMenuView.setProp(device == Device.FINGER ? fingerHighlighterProp : stylusHighlighterProp);
            }

            updatePenUi(device == Device.FINGER ? fingerPenProp : stylusPenProp);
            updateHighlighterUi(device == Device.FINGER ? fingerHighlighterProp
                    : stylusHighlighterProp);

            if (floatingBarView != null) {
                switch (input) {
                    case PEN: {
                        floatingBarView.syncInputFromMain(0);
                        break;
                    }
                    case HIGHLIGHTER: {
                        floatingBarView.syncInputFromMain(1);
                        break;
                    }
                    case OBJECT_ERASER: {
                        floatingBarView.syncInputFromMain(2);
                        break;
                    }
                }

                floatingBarView.setPenProp(device == Device.FINGER ? fingerPenProp : stylusPenProp);
                floatingBarView.setHighlighterProp(device == Device.FINGER ? fingerHighlighterProp
                        : stylusHighlighterProp);
            }

            switch (input) {
                case AUTOSHAPE:
                    if (inputAutoshape != null) {
                        toggleInput(inputAutoshape);
                    }
                    break;
                case OBJECT_ERASER:
                case PARTIAL_ERASER:
                    toggleInput(inputEraser);
                    break;
                case HIGHLIGHTER:
                    toggleInput(inputHighlighter);
                    break;
                case PEN:
                    toggleInput(inputPen);
                    break;
                case SELECT:
                    if (inputSelect != null) {
                        toggleInput(inputSelect);
                    }
                    break;
                case TEXT:
                    if (inputText != null) {
                        toggleInput(inputText);
                    }
                    break;
                case MOVE_CANVAS:
                    if (inputMoveCanvas != null) {
                        toggleInput(inputMoveCanvas);
                    }
                    break;

            }
        });
    }

    /**
     * Adds a new page if limit has not been exceeded.
     */
    private void addNewPage() {
        if (states.size() == maxNumWhiteboardStates) {
            showToast(getString(R.string.alert_pages_limit));
            return;
        }

        if (pageProp.getPattern() == PageProperty.Pattern.IMPORT) {
            if (backgroundTarget != null) {
                GlideApp.with(getApplicationContext()).load(pageProp.getCustomBackground()).override(1920, 1080).
                        into(backgroundTarget);
            } else {
                GlideApp.with(getApplicationContext()).load(pageProp.getCustomBackground()).override(1920, 1080).
                        into(backgroundTarget = new CustomTarget<Drawable>() {
                            @Override
                            public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
                                final WhiteboardState state = new WhiteboardState(pageProp.getColor(),
                                        pageProp.getPattern(), resource,
                                        fileHelper.generateFileName(false), false);
//                        mSettings.setPageMenuSettingColor(state.getPageColor());
//                        mSettings.setPageMenuSettingPattern(state.getPagePattern());
                                if (stateIndex == states.size() - 1) {
                                    // update current page json file
                                    saveStateToJson(stateIndex);

                                    states.add(state);
                                    stateIndex++;
                                } else {
                                    // update names of json files because a page is inserted.
                                    // Rename those json files first then update the current page whose index has been changed to stateIndex + 1.
                                    stateFileSaver.updateJsonNameAfterInsertNewPage(stateIndex + 1, states.size());

                                    saveStateToJson(stateIndex + 1);
                                    states.add(++stateIndex, state);
                                }

                                // hitevision debug
                                if (state.getPagePattern() == PageProperty.Pattern.IMPORT && state.getPageCustomBackground() != null) {
                                    state.setCustomBackgroundName(pageProp.getCustomBackgroundName());
                                }

                                whiteboard.queueInput(InputEvent.createSetStateAction(state));
                                updatePageNumber(state);
                            }

                            @Override
                            public void onLoadCleared(@Nullable Drawable placeholder) {

                            }
                        });
            }
        } else {
            final WhiteboardState state = new WhiteboardState(pageProp.getColor(),
                    pageProp.getPattern(), pageProp.getCustomBackground(),
                    fileHelper.generateFileName(false), false);
            if (stateIndex == states.size() - 1) {
                // update current page json file
                saveStateToJson(stateIndex);

                states.add(state);
                stateIndex++;
            } else {
                // update names of json files because a page is inserted.
                // Rename those json files first then update the current page whose index has been changed to stateIndex + 1.
                stateFileSaver.updateJsonNameAfterInsertNewPage(stateIndex + 1, states.size());

                saveStateToJson(stateIndex + 1);
                states.add(++stateIndex, state);
            }

            // hitevision debug
            if (state.getPagePattern() == PageProperty.Pattern.IMPORT && state.getPageCustomBackground() != null) {
                state.setCustomBackgroundName(pageProp.getCustomBackgroundName());
            }

            whiteboard.queueInput(InputEvent.createSetStateAction(state));
            updatePageNumber(state);
        }


//        final WhiteboardState state = new WhiteboardState(pageProp.getColor(),
//                pageProp.getPattern(), pageProp.getCustomBackground(),
//                fileHelper.generateFileName(false), false);
//        mSettings.setPageMenuSettingColor(state.getPageColor());
//        mSettings.setPageMenuSettingPattern(state.getPagePattern());
//        if (stateIndex == states.size() - 1) {
//            states.add(state);
//            stateIndex++;
//        } else {
//            states.add(++stateIndex, state);
//        }
//
//        whiteboard.queueInput(InputEvent.createSetStateAction(state));
//        updatePageNumber(state);
    }

    private void backPage() {
        if (stateIndex == 0) {
            showToast(getString(R.string.alert_pages_beginning));
            return;
        }

        saveStateToJson(stateIndex);

        stateIndex--;
        final WhiteboardState state = states.get(stateIndex);
        whiteboard.queueInput(InputEvent.createSetStateAction(state));
        updatePageNumber(state);

        pageChanges++;
        checkPageChanges();
    }

    private void nextPage() {
        if (stateIndex == states.size() - 1) {
            showToast(getString(R.string.alert_pages_end));
            return;
        }

        saveStateToJson(stateIndex);

        stateIndex++;
        final WhiteboardState state = states.get(stateIndex);
        whiteboard.queueInput(InputEvent.createSetStateAction(state));
        updatePageNumber(state);

        pageChanges++;
        checkPageChanges();
    }

    private void checkPageChanges() {
        if (pageChanges >= pageChangesLimit) {
            GlideApp.get(getApplicationContext()).clearMemory();
            System.gc();

            pageChanges = 0;
        }
    }

    private void confirmClearAll() {
        if (dialog == null) {
            initWhiteboardDialogView();
        }
        dialog.setTitle(Props.getFlavorModel().equals(Props.Flavor.Model.Oem) ? null : getString(R.string.clear_all_title));
        dialog.setContent(getString(R.string.clear_all_content));
        dialog.setPositiveButton(getString(R.string.button_clear), onClearAllDialogClickListener);
        dialog.setNegativeButton(getString(R.string.button_cancel), null);
        dialog.setVisibility(View.VISIBLE);
    }

    private final WhiteboardDialog.OnDialogClickListener onClearAllDialogClickListener
            = (dialog, button) -> {
        whiteboard.queueInput(InputEvent.createAction(InputEvent.Action.CLEAR_BOARD));
    };

    private void showAutoScreenshotDialog() {
        if (dialog == null) {
            initWhiteboardDialogView();
        }
        dialog.setTitle(getString(R.string.auto_screenshot_title));
        dialog.setContent(getString(R.string.auto_screenshot_content));
        dialog.setPositiveButton(getString(R.string.button_yes), onAutoScreenshotDialogClickListener);
        dialog.setNegativeButton(getString(R.string.button_no), onAutoScreenshotDialogClickListener);
        dialog.show();
    }

    /**
     * 19B 批注模式下截图后，是否跳转到白板
     */
    private void showAutoJmp2WhiteboardDialog() {
        if (null == dialog)
            initWhiteboardDialogView();
        dialog.setTitle("自动跳转白板");
        dialog.setContent("自动跳转到白板？");
        dialog.setPositiveButton("是", onAutoJmp2WhiteboardDialogClickListener);
        dialog.setNegativeButton("否", onAutoJmp2WhiteboardDialogClickListener);
        dialog.show();
    }

    private final WhiteboardDialog.OnDialogClickListener onAutoScreenshotDialogClickListener
            = (dialog, button) -> {
        isAutoScreenshotEnabled = button == WhiteboardDialog.BUTTON_POSITIVE;
        mSettings.setAutoScreenshotEnabled(isAutoScreenshotEnabled);
    };

    private final WhiteboardDialog.OnDialogClickListener onAutoJmp2WhiteboardDialogClickListener
            = (dialog, button) -> {
        log("======>>>>>>lastScreenshotFileName=" + lastScreenshotFileName);
        handler.postDelayed(() -> {
            if (button == WhiteboardDialog.BUTTON_POSITIVE) {//19B批注模式下截图后是否跳转白板并插入截图
                Intent startIntent = new Intent(this, MainActivity.class);
                startIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                startIntent.putExtra(FileHelper.FILE_PATH, Environment.getExternalStorageDirectory().getPath() + FileHelper.FOLDER_SCREENSHOTS + FileHelper.FOLDER_IMAGE + File.separator + lastScreenshotFileName);
                startIntent.putExtra(EXTRA_ANNOTATION_MODE, false);
                startActivity(startIntent);
            }
        }, 7000);
    };

    private void setInputAutoshapeForAnnotationMode(boolean enabled) {
        if (Props.getFlavorModel().equals(Props.Flavor.Model.Oem)) {
            ConstraintSet constraintSet = new ConstraintSet();
            ConstraintLayout constraintLayout = findViewById(R.id.rootLayout);
            constraintSet.clone(constraintLayout);
            if (enabled) {
                constraintSet.clear(R.id.add_autoshape, ConstraintSet.BOTTOM);
                constraintSet.clear(R.id.add_autoshape, ConstraintSet.START);
                constraintSet.clear(R.id.move_canvas, ConstraintSet.START);
                constraintSet.connect(R.id.input_select, ConstraintSet.START, R.id.add_autoshape, ConstraintSet.END);
                constraintSet.connect(R.id.add_autoshape, ConstraintSet.BOTTOM, R.id.input_pen, ConstraintSet.BOTTOM);
                constraintSet.connect(R.id.add_autoshape, ConstraintSet.END, R.id.input_select, ConstraintSet.START);
                constraintSet.connect(R.id.add_autoshape, ConstraintSet.START, R.id.input_highlighter, ConstraintSet.END);
                constraintSet.connect(R.id.input_highlighter, ConstraintSet.END, R.id.add_autoshape, ConstraintSet.START);
                constraintSet.setHorizontalBias(R.id.add_autoshape, (float) 0.5);
                constraintSet.setMargin(R.id.add_autoshape, ConstraintSet.END, getResources().getDimensionPixelSize(R.dimen.bottom_bar_middle_icon_margin));
                constraintSet.applyTo(constraintLayout);
            } else {
                constraintSet.clear(R.id.add_autoshape, ConstraintSet.END);
                constraintSet.setMargin(R.id.add_autoshape, ConstraintSet.START, getResources().getDimensionPixelSize(R.dimen.bottom_bar_icon_margin));
                constraintSet.connect(R.id.input_select, ConstraintSet.START, R.id.input_highlighter, ConstraintSet.END);
                constraintSet.connect(R.id.input_highlighter, ConstraintSet.END, R.id.input_select, ConstraintSet.START);
                constraintSet.connect(R.id.add_autoshape, ConstraintSet.BOTTOM, ConstraintSet.PARENT_ID, ConstraintSet.BOTTOM);
                constraintSet.connect(R.id.add_autoshape, ConstraintSet.START, R.id.add_text, ConstraintSet.END);
                constraintSet.connect(R.id.move_canvas, ConstraintSet.START, R.id.add_autoshape, ConstraintSet.END);
                constraintSet.setMargin(R.id.move_canvas, ConstraintSet.START, getResources().getDimensionPixelSize(R.dimen.bottom_bar_icon_margin));
                constraintSet.applyTo(constraintLayout);
            }
        } else {
            if (enabled) {
                inputAutoshape.setVisibility(GONE);
            } else {
                inputAutoshape.setVisibility(View.VISIBLE);
            }
        }
    }

    private void setUiForAnnotationMode(boolean enabled) {
        if (inputAutoshape != null) {
            setInputAutoshapeForAnnotationMode(enabled);
        }
        if (enabled) {
            if (Props.getFlavorModel().equals(Props.Flavor.Model.Oem)) {
//                bottomBarBackground.setSelected(true);
//                bottomBarBackground.requestLayout();
                bottomBarBackground.setVisibility(View.GONE);
                oemAnnotationBackground.setVisibility(View.VISIBLE);
                if (settings != null && oemAnnotationSettings != null) {
                    settings.setVisibility(View.GONE);
                    oemAnnotationSettings.setVisibility(View.VISIBLE);
                }
                changeSettingsMenuConstrainLayout(true);
            }
            if (plugins != null) {
                plugins.setVisibility(View.GONE);
            }
            if (addImage != null) {
                addImage.setVisibility(View.GONE);
            }
            if (inputText != null) {
                inputText.setVisibility(View.GONE);
            }
            if (addPage != null) {
                addPage.setVisibility(View.GONE);
            }
            if (backPage != null) {
                backPage.setVisibility(View.GONE);
            }
            if (nextPage != null) {
                nextPage.setVisibility(View.GONE);
            }
            if (toggleControl != null) {
                if (toggleBar != null) {
                    toggleBar.setVisibility(View.VISIBLE);
                }
                if (!Props.getFlavorModel().equals(Props.Flavor.Model.Wcd) && displayControl.isSupported(this)) {
                    toggleControl.setVisibility(View.VISIBLE);
                }
                if (oemBottomBarLeftDivider != null) {
                    oemBottomBarLeftDivider.setVisibility(toggleControl.getVisibility());
                }
            }
            takeScreenshot.setVisibility(View.VISIBLE);
            if (navigator != null) {
                if (!Props.getFlavorModel().equals(Props.Flavor.Model.Rs)) {
                    navigator.setVisibility(View.GONE);
                } else {
                    navigatorView.setAnnotationMode(true);
                }
            }
            if (exit != null) {
                exit.setVisibility(View.VISIBLE);
            }
//            if (settingsMenuView != null) {
//                if (Props.getFlavorModel().equals(Props.Flavor.Model.Rs)) {
//                    settingsMenuView.setOffsetRight(getResources().getDimensionPixelOffset(R.dimen.settings_menu_annotation_offset_right));
//                }
//            }
            if (inputMoveCanvas != null) {
                inputMoveCanvas.setVisibility(View.GONE);
            }
            if (oemBottomBarRightDivider != null) {
                oemBottomBarRightDivider.setVisibility(View.VISIBLE);
            }
            if (exitWhiteboard != null) {
                exitWhiteboard.setVisibility(GONE);
            }
        } else {
            if (Props.getFlavorModel().equals(Props.Flavor.Model.Oem)) {
//                bottomBarBackground.setSelected(false);
//                bottomBarBackground.requestLayout();s
                bottomBarBackground.setVisibility(View.VISIBLE);
                oemAnnotationBackground.setVisibility(View.GONE);
                if (settings != null && oemAnnotationSettings != null) {
                    settings.setVisibility(View.VISIBLE);
                    oemAnnotationSettings.setVisibility(View.GONE);
                }
                changeSettingsMenuConstrainLayout(false);
            }
            if (plugins != null) {
                plugins.setVisibility(View.VISIBLE);
            }
            if (addImage != null) {
                addImage.setVisibility(View.VISIBLE);
            }
            if (inputText != null) {
                inputText.setVisibility(View.VISIBLE);
            }
            if (addPage != null) {
                addPage.setVisibility(View.VISIBLE);
            }
            if (backPage != null) {
                backPage.setVisibility(View.VISIBLE);
            }
            if (nextPage != null) {
                nextPage.setVisibility(View.VISIBLE);
            }
            if (toggleControl != null) {
                if (toggleBar != null) {
                    toggleBar.setVisibility(View.GONE);
                }
                if (!Props.getFlavorModel().equals(Props.Flavor.Model.Wcd)) {
                    toggleControl.setVisibility(View.GONE);
                }
                if (oemBottomBarLeftDivider != null) {
                    oemBottomBarLeftDivider.setVisibility(toggleControl.getVisibility());
                }
            }
            takeScreenshot.setVisibility(View.GONE);
            if (navigator != null) {
                if (!Props.getFlavorModel().equals(Props.Flavor.Model.Rs)) {
                    navigator.setVisibility(View.VISIBLE);
                } else {
                    navigatorView.setAnnotationMode(false);
                }
            }
            if (exit != null) {
                exit.setVisibility(View.GONE);
            }
//            if (settingsMenuView != null) {
//                if (Props.getFlavorModel().equals(Props.Flavor.Model.Rs)) {
//                    settingsMenuView.setOffsetRight(0);
//                }
//            }
            if (inputMoveCanvas != null) {
                inputMoveCanvas.setVisibility(View.VISIBLE);
            }
            if (oemBottomBarRightDivider != null) {
                oemBottomBarRightDivider.setVisibility(View.GONE);
            }
            if (oemBottomBarLeftDivider != null) {
                oemBottomBarLeftDivider.setVisibility(View.GONE);
            }
        }
    }

    private void changeSettingsMenuConstrainLayout(boolean isAnnotationState) {
        ConstraintLayout rootLayout = findViewById(R.id.rootLayout);

        ConstraintSet constraintSet = new ConstraintSet();
        int margin = getResources().getDimensionPixelSize(R.dimen.settings_menu_margin_bottom);
        int marginStart = getResources().getDimensionPixelSize(R.dimen.settings_menu_margin_start);

        if (settingsMenuView == null)
            initSettingsMenuView();
        settingsMenuView.setAnnotationBackground(isAnnotationState);
        if (isAnnotationState) {
            constraintSet.clone(rootLayout);
            constraintSet.connect(R.id.view_stub_settings_menu_view, ConstraintSet.BOTTOM, R.id.oem_annotation_settings, ConstraintSet.TOP, margin);
            constraintSet.connect(R.id.view_stub_settings_menu_view, ConstraintSet.END, R.id.oem_annotation_settings, ConstraintSet.END, 0);
            constraintSet.connect(R.id.view_stub_settings_menu_view, ConstraintSet.START, R.id.oem_annotation_settings, ConstraintSet.START, 0);
            constraintSet.applyTo(rootLayout);
        } else {
            constraintSet.clone(rootLayout);
            constraintSet.connect(R.id.view_stub_settings_menu_view, ConstraintSet.BOTTOM, R.id.settings, ConstraintSet.TOP, margin);
            constraintSet.connect(R.id.view_stub_settings_menu_view, ConstraintSet.END, R.id.settings, ConstraintSet.END, 0);
            constraintSet.connect(R.id.view_stub_settings_menu_view, ConstraintSet.START, R.id.settings, ConstraintSet.START, marginStart);
            constraintSet.applyTo(rootLayout);
        }
    }

    // click on toggleControl
    private void setDisplayControlMode(boolean enabled) {
        isDisplayControlModeEnabled = enabled;

//        boolean touchEnable = whiteboard.getState().isAnnotationState() && toggleControl.isSelected();
//        Intent intent = new Intent((touchEnable && enabled) ? DisplayControlImpl.USBTOUCH_ENABLE : DisplayControlImpl.USBTOUCH_DISABLE);
//        intent.putExtra(DisplayControlImpl.isSetOnButton, true);
//        displayControl.setIntent(intent);
//        log("displayControl : setDisplayControlMode, enabled : " + enabled);

        displayControlNChina.toggleDisplayControl(getApplicationContext(), enabled);

        if (enabled) {
            if (Props.getFlavorModel().equals(Props.Flavor.Model.Oem)) {
                setDisabledBoundsForDisplayControl(oemAnnotationBackground);
            } else {
                setDisabledBoundsForDisplayControl(bottomBarBackground);
            }
            displayControl.start(this);
        } else {
            displayControl.stop(this);
        }
    }

    private void setBottomBarVisible(boolean visible) {
        final int visibility = visible ? View.VISIBLE : View.GONE;

//        bottomBarBackground.setVisibility(visibility);
        // todo : seems will not get in the following if , check later
        if (Props.getFlavorModel().equals(Props.Flavor.Model.Oem) && oemAnnotationBackground != null && oemAnnotationSettings != null) {
            if (visible) {
                if (whiteboard.getState().isAnnotationState()) {
                    oemAnnotationBackground.setVisibility(View.VISIBLE);
                    bottomBarBackground.setVisibility(View.GONE);
                    if (settings != null && oemAnnotationSettings != null) {
                        settings.setVisibility(View.GONE);
                        oemAnnotationSettings.setVisibility(View.VISIBLE);
                        changeSettingsMenuConstrainLayout(true);
                    }
                } else {
                    oemAnnotationBackground.setVisibility(View.GONE);
                    bottomBarBackground.setVisibility(View.VISIBLE);
                    if (settings != null && oemAnnotationSettings != null) {
                        settings.setVisibility(View.VISIBLE);
                        oemAnnotationSettings.setVisibility(View.GONE);
                        changeSettingsMenuConstrainLayout(false);
                    }
                }
            } else {
                oemAnnotationBackground.setVisibility(View.GONE);
                bottomBarBackground.setVisibility(View.GONE);
                settings.setVisibility(View.GONE);
                oemAnnotationSettings.setVisibility(View.GONE);
            }
        } else {
            bottomBarBackground.setVisibility(visibility);
        }
        if (toggleControl != null && !Props.getFlavorModel().equals(Props.Flavor.Model.Wcd)) {
            if (displayControl.isSupported(this)) {
                toggleControl.setVisibility(visibility);
            } else {
                toggleControl.setVisibility(View.GONE);
            }
            if (oemBottomBarLeftDivider != null) {
                oemBottomBarLeftDivider.setVisibility(toggleControl.getVisibility());
            }
        }
        if (oemBottomBarRightDivider != null)
            oemBottomBarRightDivider.setVisibility(visibility);
        inputPen.setVisibility(visibility);
        inputHighlighter.setVisibility(visibility);
        if (inputSelect != null) {
            inputSelect.setVisibility(visibility);
        }
        if (inputAutoshape != null) {
            inputAutoshape.setVisibility(visibility);
        }
        inputEraser.setVisibility(visibility);
        clearAll.setVisibility(visibility);
        undo.setVisibility(visibility);
        if (redo != null) {
            redo.setVisibility(visibility);
        }
        takeScreenshot.setVisibility(visibility);
        if (share != null) {
            share.setVisibility(visibility);
        }
        if (exit != null) {
            exit.setVisibility(visibility);
        }
        buildInfoButton.setVisibility(visibility);
        if (inputSelect != null) {
            inputSelect.setVisibility(visibility);
        }
        if (switchMode != null) {
            switchMode.setVisibility(visibility);
        }
//        if (settings != null) {
        if (settings != null && oemAnnotationSettings == null) {
            settings.setVisibility(visibility);
        }
        if (displayControl.isSupported(this) && displayControl.isRunning()) {
            if (visible) {
                setDisabledBoundsForDisplayControl(bottomBarBackground);
            } else {
                if (toggleBar != null && !isTakingScreenshot) {
                    setDisabledBoundsForDisplayControl(toggleBar);
                }
            }
        }
        if (navigator != null && Props.getFlavorModel().equals(Props.Flavor.Model.Rs)) {
            navigator.setVisibility(visibility);
        }
    }

    /**
     * Takes a screenshot.
     *
     */
    private void onclickTakeScreenshot() {
        isTakingScreenshot = true;

        // notify floatbar that app is taking a screenshot
        BroadcastHelper.sendScreenshotStart(this);

        // disable take screenshot button
        if (takeScreenshot != null) {
            takeScreenshot.setEnabled(false);
        }

        // play shutter click sound
        if (actionSound == null) {
            actionSound = new MediaActionSound();
            actionSound.load(MediaActionSound.SHUTTER_CLICK);
        }

        if (actionSound != null) {
            actionSound.play(MediaActionSound.SHUTTER_CLICK);
        }

        final boolean isAnnotationState = whiteboard.getState().isAnnotationState();


        final boolean isBottomBarVisible = toggleBar == null || !toggleBar.isSelected();
        final boolean isToggleBarVisible = toggleBar != null && toggleBar.getVisibility() == View.VISIBLE;
        setBottomBarVisible(false);
        if (toggleBar != null) {
            toggleBar.setVisibility(View.GONE);
            if (Props.getFlavorModel().equals(Props.Flavor.Model.Oem) && toggleControl.getVisibility() == View.GONE) {
                if (oemBottomBarLeftDivider != null) {
                    oemBottomBarLeftDivider.setVisibility(View.GONE);
                }
            }
        }

        if (paste != null) {
            paste.setVisibility(View.GONE);
        }
        if (selectionView != null) {
            selectionView.hide();
        }
        clearSelection();

        // delay taking screenshot to allow floatbar to respond to start-screenshot intent
        handler.postDelayed(() -> {
            // take screenshot
            View decor = getWindow().getDecorView();
            Bitmap screenshot = SurfaceControlUtils.startScreenShot(decor.getWidth(), decor.getHeight());
            if (screenshot != null) {
                // save screenshot
                screenshotHelper.animate(null, new ScreenshotHelper.OnAnimationEndListener() {
                    @Override
                    public void onAnimationEnd() {

                    }
                });
                lastScreenshotFileName = fileHelper.generateFileName(isAnnotationState);

//                mGlobalScreenShot.setScreenShotImg(screenshot);
//                mGlobalScreenShot.doAnimation();
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        FileHelper fileHelper = FileHelper.getInstance(MainActivity.this);
                        fileHelper.saveToFile(MainActivity.this, screenshot, lastScreenshotFileName, null);
                    }
                }).start();


                //  fileHandler.sendSaveImageMessage(null, lastScreenshotFileName);

                // animate taking a screenshot

                //    }

                handler.postDelayed(() -> {
                    // clean up
                    if (isBottomBarVisible) {
                        setBottomBarVisible(true);
                    }
                    if (isToggleBarVisible) {
                        toggleBar.setVisibility(View.VISIBLE);
                        if (Props.getFlavorModel().equals(Props.Flavor.Model.Oem) && toggleControl.getVisibility() == View.VISIBLE) {
                            if (oemBottomBarLeftDivider != null) {
                                oemBottomBarLeftDivider.setVisibility(View.VISIBLE);
                            }
                        }
                    }

                    if (takeScreenshot != null) {
                        takeScreenshot.setEnabled(true);
                    }

                    isTakingScreenshot = false;
                    if (Props.getFlavorModel().equals(Props.Flavor.Model.Oem) && Props.getFlavorChipset().equals(Props.Flavor.Chipset.Mstar)) {
//                    showAutoJmp2WhiteboardDialog();
                    }
                }, 1000);

                // if screenshot failed, call onAnimationEnd() manually
//            if ( onAnimationEndListener != null) {
//                onAnimationEndListener.onAnimationEnd();
            }
        }, mSettings.isFake4k() ? UI_CHANGE_DELAY_4K : UI_CHANGE_DELAY_2K);
    }


    private void beforeTakeScreen() {
        isTakingScreenshot = true;

        // notify floatbar that app is taking a screenshot
        BroadcastHelper.sendScreenshotStart(this);

        // disable take screenshot button
        if (takeScreenshot != null) {
            takeScreenshot.setEnabled(false);
        }

        // play shutter click sound
        if (actionSound == null) {
            actionSound = new MediaActionSound();
            actionSound.load(MediaActionSound.SHUTTER_CLICK);
        }

        if (actionSound != null) {
            actionSound.play(MediaActionSound.SHUTTER_CLICK);
        }
        setBottomBarVisible(false);
        if (toggleBar != null) {
            toggleBar.setVisibility(View.GONE);
            if (Props.getFlavorModel().equals(Props.Flavor.Model.Oem) && toggleControl.getVisibility() == View.GONE) {
                if (oemBottomBarLeftDivider != null) {
                    oemBottomBarLeftDivider.setVisibility(View.GONE);
                }
            }
        }

        if (paste != null) {
            paste.setVisibility(View.GONE);
        }
        if (selectionView != null) {
            selectionView.hide();
        }
        clearSelection();

    }

    private void afterTakeScreen() {
        final boolean isBottomBarVisible = toggleBar == null || !toggleBar.isSelected();
        final boolean isToggleBarVisible = toggleBar != null && toggleBar.getVisibility() == View.VISIBLE;
        if (isBottomBarVisible) {
            setBottomBarVisible(true);
        }
        if (isToggleBarVisible) {
            toggleBar.setVisibility(View.VISIBLE);
            if (Props.getFlavorModel().equals(Props.Flavor.Model.Oem) && toggleControl.getVisibility() == View.VISIBLE) {
                if (oemBottomBarLeftDivider != null) {
                    oemBottomBarLeftDivider.setVisibility(View.VISIBLE);
                }
            }
        }

        if (takeScreenshot != null) {
            takeScreenshot.setEnabled(true);
        }

        isTakingScreenshot = false;
    }

    private Bitmap screenshot = null;

    /**
     * Takes a screenshot.
     *
     * @param onAnimationEndListener listener for when screenshot animation ends, may be {@code null}
     */
    @SuppressLint("CheckResult")
    private void onClickTakeScreenshot(@Nullable ScreenshotHelper.OnAnimationEndListener onAnimationEndListener) {

        final boolean isAnnotationState = whiteboard.getState().isAnnotationState();
        lastScreenshotFileName = fileHelper.generateFileName(isAnnotationState);
        beforeTakeScreen();
        handler.postDelayed(() -> {
            Observable.just(lastScreenshotFileName)
                    .map(path -> {
//                        Log.e("Hogan", "apply--"+Thread.currentThread().getName());
                        if (screenshot != null) {
                            fileHelper.saveToFile(MainActivity.this, screenshot, path, null);
                            return "success";
                        }
                        return "fail";
                    }).subscribeOn(Schedulers.io())
                    .doOnSubscribe(disposable -> {
//                        Log.e("Hogan", "disposable----"+Thread.currentThread().getName());
                        screenshot = SurfaceControlUtils.startScreenShot(1920, 1080);
                        screenshotHelper.animate(screenshot, onAnimationEndListener);
                    })
                    .onErrorReturn(throwable -> "fail")
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(s -> {
//                        Log.e("Hogan", s + "----" + Thread.currentThread().getName());
                        afterTakeScreen();
                        if (screenshot == null && onAnimationEndListener != null) {
                            onAnimationEndListener.onAnimationEnd();
                        }
                    });
        }, mSettings.isFake4k() ? UI_CHANGE_DELAY_4K : UI_CHANGE_DELAY_2K);
    }


    /**
     * Takes a screenshot.
     *
     * @param onAnimationEndListener listener for when screenshot animation ends, may be {@code null}
     */
    private void takeScreenshot(@Nullable ScreenshotHelper.OnAnimationEndListener
                                        onAnimationEndListener) {
        isTakingScreenshot = true;

        // notify floatbar that app is taking a screenshot
        BroadcastHelper.sendScreenshotStart(this);

        // disable take screenshot button
        if (takeScreenshot != null) {
            takeScreenshot.setEnabled(false);
        }

        // play shutter click sound
        if (actionSound == null) {
            actionSound = new MediaActionSound();
            actionSound.load(MediaActionSound.SHUTTER_CLICK);
        }

        if (actionSound != null) {
            actionSound.play(MediaActionSound.SHUTTER_CLICK);
        }

        final boolean isAnnotationState = whiteboard.getState().isAnnotationState();


        final boolean isBottomBarVisible = toggleBar == null || !toggleBar.isSelected();
        final boolean isToggleBarVisible = toggleBar != null && toggleBar.getVisibility() == View.VISIBLE;
        setBottomBarVisible(false);
        if (toggleBar != null) {
            toggleBar.setVisibility(View.GONE);
            if (Props.getFlavorModel().equals(Props.Flavor.Model.Oem) && toggleControl.getVisibility() == View.GONE) {
                if (oemBottomBarLeftDivider != null) {
                    oemBottomBarLeftDivider.setVisibility(View.GONE);
                }
            }
        }

        if (paste != null) {
            paste.setVisibility(View.GONE);
        }
        if (selectionView != null) {
            selectionView.hide();
        }
        clearSelection();

        // delay taking screenshot to allow floatbar to respond to start-screenshot intent
        handler.postDelayed(() -> {
            // take screenshot
            final View decor = getWindow().getDecorView();
            final Bitmap screenshot = SurfaceControlUtils.takeScreenshot(decor.getWidth(), decor.getHeight());
            if (screenshot != null) {
                // save screenshot
                lastScreenshotFileName = fileHelper.generateFileName(isAnnotationState);
                fileHandler.sendSaveImageMessage(screenshot, lastScreenshotFileName);

                // animate taking a screenshot
                screenshotHelper.animate(screenshot, onAnimationEndListener);
            }

            handler.postDelayed(() -> {
                // clean up
                if (isBottomBarVisible) {
                    setBottomBarVisible(true);
                }
                if (isToggleBarVisible) {
                    toggleBar.setVisibility(View.VISIBLE);
                    if (Props.getFlavorModel().equals(Props.Flavor.Model.Oem) && toggleControl.getVisibility() == View.VISIBLE) {
                        if (oemBottomBarLeftDivider != null) {
                            oemBottomBarLeftDivider.setVisibility(View.VISIBLE);
                        }
                    }
                }

                if (takeScreenshot != null) {
                    takeScreenshot.setEnabled(true);
                }

                isTakingScreenshot = false;
                if (Props.getFlavorModel().equals(Props.Flavor.Model.Oem) && Props.getFlavorChipset().equals(Props.Flavor.Chipset.Mstar)) {
//                    showAutoJmp2WhiteboardDialog();
                }
            }, 1000);

            // if screenshot failed, call onAnimationEnd() manually
            if (screenshot == null && onAnimationEndListener != null) {
                onAnimationEndListener.onAnimationEnd();
            }
        }, mSettings.isFake4k() ? UI_CHANGE_DELAY_4K : UI_CHANGE_DELAY_2K);
    }

    private final ScreenshotHelper.OnAnimationEndListener takeScreenshotAfterAnimationListener
            = () -> {
        BroadcastHelper.sendScreenshotEnd(this);
    };

    private final ScreenshotHelper.OnAnimationEndListener finishAfterAnimationListener
            = () -> {
        if (displayControl.isRunning()) {
//            Intent intent = new Intent(DisplayControlImpl.USBTOUCH_ENABLE);
//            displayControl.setIntent(intent);
            displayControlNChina.enableUsbTouch(this);
            displayControl.stop(this);
            log("displayControl : finishAfterAnimationListener");
        }

        BroadcastHelper.sendScreenshotEndAndAppIsFinishing(this);

        setExitOnAnnotationModeSystemProp();

        isFinishing = true;

        finish();
    };

    private final ScreenshotHelper.OnAnimationEndListener hideAfterAnimationListener
            = () -> {
        if (displayControl.isRunning()) {
//            Intent intent = new Intent(DisplayControlImpl.USBTOUCH_ENABLE);
//            displayControl.setIntent(intent);
            displayControlNChina.enableUsbTouch(this);
            displayControl.stop(this);
            log("displayControl : hideAfterAnimationListener");
        }
        BroadcastHelper.sendScreenshotEndAndAppIsFinishing(this);

        InputManager inputManager = InputManager.getInstance();

        // reset annotation state
        inputManager.reset();
        annotationState.clearItems();
        @ColorInt int penBlack = ContextCompat.getColor(this, R.color.pen_black);
        @ColorInt int penRed = ContextCompat.getColor(this, R.color.pen_red);
        @ColorInt int highligherRed = ContextCompat.getColor(this, R.color.highlight_red);
        annotationFingerPenProp.set(penRed, PenProperty.Size.ONE);
        annotationStylusPenProp.set(penBlack, PenProperty.Size.ONE);
        annotationFingerHighlighterProp.set(highligherRed, HighlighterProperty.Size.TWO);
        annotationStylusHighlighterProp.set(highligherRed, HighlighterProperty.Size.TWO);

        toggleInput(inputManager.getInput(Device.FINGER) == Whiteboard.Input.HIGHLIGHTER
                ? inputHighlighter : inputPen);
        updateInputUi(true);

        whiteboard.queueInput(InputEvent.createAction(InputEvent.Action.CLEAR_BOARD));

        setExitOnAnnotationModeSystemProp();

        isFinishing = false;
        Log.d("wjj", "isSelected22");
        moveTaskToBack(true);
    };

    private final ScreenshotHelper.OnAnimationEndListener shareAfterAnimationListener
            = () -> {
        log("shareAfterAnimationListener");
        shareScreenshot();
        BroadcastHelper.sendScreenshotEnd(this);
    };

    /**
     * Notify system that app is exiting in annotation mode.
     */
    private void setExitOnAnnotationModeSystemProp() {
        log("setExitOnAnnotationModeSystemProp");
        // set system property only if the activity underneath is launcher app
        final int numOfTasks = 2;
        final List<ActivityManager.RunningTaskInfo> tasks = ActivityUtils.getRunningTasks(this, numOfTasks);
        if (tasks.size() == numOfTasks) {
            if (tasks.get(numOfTasks - 1).topActivity.flattenToString().equals(ActivityUtils.ACTIVITY_LAUNCHER)) {
                log("- launcher is underneath, setting true");
                SystemPropertiesUtils.setValue(SystemPropertiesUtils.KEY_NOTIFY_EXIT_ON_ANNOTATION, "true");
            } else {
                log("- launcher is not underneath, do nothing");
            }
        }
    }

    private void setDisabledBoundsForDisplayControl(View v) {
        if (v != null) {
            final int x = (int) v.getX();
            final int y = (int) v.getY();
            final int width = v.getWidth();
            final int height = v.getHeight();

            if (width != 0 && height != 0) {
                displayControl.setDisabledBounds(x, y, width, height);
            }
        }
    }

    @Override
    public void onStart() {
        super.onStart();

        if(whiteboard.getState().isAnnotationState()  &&
                (Props.getFlavorChipset().equals(Props.Flavor.Chipset.Amlogic))) {
            Thread t = new Thread(new Runnable() {
                @Override
                public void run() {
                    Instrumentation instrumentation = new Instrumentation();
                    instrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_MEDIA_PAUSE);
                }
            });
            t.start();
        }
        log("onStart");
        BroadcastHelper.sendCheckOpsTouch(this);
        registerHhtActionBroadcastReceiver();

        if(WbJniCall.isLoaded() && Props.getFlavorChipset().equals(Props.Flavor.Chipset.Optoma))
            WbJniCall.fbShowGop(true);

//        registerEndMeetingReceiver();
    }

    private final Runnable checkToggleControl = new Runnable() {
        @Override
        public void run() {
            final boolean visible = displayControl.isSupported(MainActivity.this) && !isTakingScreenshot;
            if (!visible) {
                toggleControl.setVisibility(View.GONE);
            } else {
                if (checkToggleControlCount < MAX_CHECK_TOGGLE_CONTROL_COUNT) {
                    checkToggleControlCount++;
                    handler.postDelayed(checkToggleControl, CHECK_TOGGLE_CONTROL_DELAY);
                } else {
//                    toggleControl.setVisibility(View.VISIBLE);
                    if (bottomBarBackground.getVisibility() == View.VISIBLE || (oemAnnotationBackground != null &&
                            oemAnnotationBackground.getVisibility() == View.VISIBLE)) {
                        toggleControl.setVisibility(View.VISIBLE);
                    }
                }
            }

            if (oemBottomBarLeftDivider != null) {
                oemBottomBarLeftDivider.setVisibility(toggleControl.getVisibility());
            }
        }
    };

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        log("onRequestPermissionsResult");
        switch (requestCode) {
            case REQUEST_PERMISSION_WRITE_STORAGE: {
                if (grantResults.length > 0 && grantResults[0] != PackageManager.PERMISSION_GRANTED) {
                    showStorageWritePermissionDialog();
                }
                break;
            }
            case REQUEST_PERMISSION_READ_STORAGE: {
                if (grantResults.length > 0 && grantResults[0] != PackageManager.PERMISSION_GRANTED) {
                    showStorageReadPermissionDialog();
                }
                break;
            }
        }
    }

    private void showStorageWritePermissionDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setMessage(R.string.request_storage_permission)
                .setPositiveButton(R.string.button_okay, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        hasRequestedStorageWritePermission = false;
                        showAppSettings();
                    }
                })
                .setCancelable(false);
        AlertDialog dialog = builder.create();
        dialog.show();
    }

    private void showStorageReadPermissionDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setMessage(R.string.request_storage_permission)
                .setPositiveButton(R.string.button_okay, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        hasRequestedStorageWritePermission = false;
                        showAppSettings();
                    }
                })
                .setCancelable(false);
        AlertDialog dialog = builder.create();
        dialog.show();
    }

    private void showAppSettings() {
        final Intent i = new Intent();
        i.setAction(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        i.addCategory(Intent.CATEGORY_DEFAULT);
        i.setData(Uri.parse("package:" + getPackageName()));
        startActivity(i);
    }

    private void resetApp() {
        log("resetApp");
        initProps();

        annotationState = new WhiteboardState(PageProperty.Color.TRANSPARENT,
                PageProperty.Pattern.BLANK, null, null, true);

        WhiteboardState state;
        boolean annotationMode;
        if (Props.getFlavorModel().equals(Props.Flavor.Model.Wcd)) {
            state = annotationState;
            annotationMode = true;
        } else {
            WhiteboardState tempState = states.get(states.size() - 1);
            states.clear();
            state = new WhiteboardState(pageProp.getColor(),
                    pageProp.getPattern(), pageProp.getCustomBackground(),
                    tempState.getPreviewFile(), false);
            states.add(state);
            stateIndex = 0;
            annotationMode = false;
        }
        whiteboard.queueInput(InputEvent.createSetStateAction(state));

        whiteboard.setAutoshapeProperty(autoshapeProp);
        whiteboard.setWordProperty(wordProp);

        if (switchMode != null) {
            switchMode.setSelected(annotationMode);
        }
        setAppMode(annotationMode);

        try {
            APIManager.connectionService(this);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        log("onResume");
        moveWhiteboardToBackground();
        if (WbJniCall.isLoaded() && Props.getFlavorChipset().equals(Props.Flavor.Chipset.Optoma))
        WbJniCall.fbShowGop(true);
        if(whiteboard.getState().isAnnotationState()  && Props.getFlavorChipset().equals(Props.Flavor.Chipset.Amlogic)) {
            Thread t = new Thread(new Runnable() {
                @Override
                public void run() {
                    Instrumentation instrumentation = new Instrumentation();
                    instrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_MEDIA_PAUSE);
                }
            });
            t.start();
        }
        if (null != floatingCursorView)
            floatingCursorView.setVisibility(GONE);

        isActivityVisible = true;

        mSettings.setDetectAppClosedForcefully(false);

        BroadcastHelper.sendAppInForeground(this, switchMode.isSelected());

        checkDisplaySettings();

        if (isWritingEyeProtectionEnabled) {
            if (backlightManager == null) {
                backlightManager = new BacklightManager(getApplicationContext());
            }
        }

        loadRulerRecord();

        // notify floatbar that app is active
        if (switchMode != null) {
            fastDraw.setAnnotationMode(switchMode.isSelected());
            BroadcastHelper.sendModeSwitch(this, switchMode.isSelected());
        } else {
            BroadcastHelper.sendModeSwitch(this, Props.getFlavorModel().equals(Props.Flavor.Model.Wcd));
        }

        if (!hasRequestedStorageWritePermission) {
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                hasRequestedStorageWritePermission = true;
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_PERMISSION_WRITE_STORAGE);
            }
        }

        if (switchMode != null && switchMode.isSelected()) {
            // check if display control is available
            if (toggleControl != null && !Props.getFlavorModel().equals(Props.Flavor.Model.Wcd)) {
                checkToggleControlCount = 0;
                handler.postDelayed(checkToggleControl, 0);
            }
        }

        if (thread != null) {
            handler.removeCallbacks(pauseThreadRunnable);
            thread.setPaused(false);
        }

        screenshotHelper.cancel();

        isOnCreateOrOnNewIntentCalled = false;

        // fix wcd device bug: display will allow touch to pass through when the app is running
        if (Props.getFlavorModel().equals(Props.Flavor.Model.Wcd)) {
            displayControl.startFromOnResume(this);
        }

        handler.postDelayed(() -> {
            whiteboard.clearWhiteBoard(false);
            whiteboard.queueInput(InputEvent.createAction(InputEvent.Action.INVALIDATE_RENDER));
        }, 500);

        if (displayControl.isSupported(this) && switchMode != null) {
            if (!switchMode.isSelected()) {
                BroadcastHelper.sendSourceAppMuteOn(this);
            }
        }

        if (!isExitSplitMenu() && !getIntent().getBooleanExtra(EXTRA_ANNOTATION_MODE, false)
                && Props.getFlavorModel().equals(Props.Flavor.Model.Oem)
                && Props.getFlavorChipset().equals(Props.Flavor.Chipset.Hisi)) {//19C 白板分屏模式下回主页后再进入白板会退出分屏模式
            log("onClickSplitMode");
            final Intent splitModeIntent = new Intent();
            splitModeIntent.setClassName(PluginsToolbarMenuView.SPLIT_MODE_PACKAGE_NAME, PluginsToolbarMenuView.SPLIT_MODE_CLASS_NAME);
            if (clearSplitMenu) {
                splitModeIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
                clearSplitMenu = false;
            }
            startActivity(splitModeIntent);//, REQUEST_GET_WEB_IMAGE);
            overridePendingTransition(0, 0);
        }

        hookWebView();

        GlideApp.get(MainActivity.this.getApplicationContext()).clearMemory();
        System.gc();

        if (Props.getFlavorChipset().equals(Props.Flavor.Chipset.Optoma)) {
//            curSourceTouchChannel = IsTouchManager.getInstance().getSourceTouchChannel();
//            IsTouchManager.getInstance().setPublicUsbToTV(true, true);
//            IsTouchManager.getInstance().setTouchChannelUSB(IsTouchManager.TOUCH_POSTPC, true);
//            Log.d("wjj", "(MT9666)KEYCODE_HOME onResume-> Android");
            IsTouchManager.getInstance().setTouchCmdConfig(8);
        }
    }

    private Runnable pauseThreadRunnable = () -> {
        if (thread != null) {
            thread.setPaused(true);
        }
    };

    @Override
    public void onPause() {
        super.onPause();
        log("onPause");

        isActivityVisible = false;

        // update the current state's preview
        whiteboard.queueInput(InputEvent.createAction(InputEvent.Action.UPDATE_STATE_PREVIEW));

        if (toggleControl != null && toggleControl.isSelected()) {
            toggleControl.callOnClick();
        }

        if (fastDraw.isDrawing()) {
            cancelFastDraw();
        }

        if (thread != null) {
            // thread will be set to null in surfaceDestroy(). SurfaceDestroy sometimes will be called before onPause.
            // It depends on machine.
            thread.setPaused(false);
        }
        handler.removeCallbacks(pauseThreadRunnable);
        handler.postDelayed(pauseThreadRunnable, 200);

        for (WhiteboardState state : states) {
            if (!state.isScreenshotTook()) {
                state.removeScreenshotFile(fileHandler);
            }
        }

        handler.removeCallbacks(checkToggleControl);

        if (postSurfaceChangedRunnable != null) {
            handler.removeCallbacks(postSurfaceChangedRunnable);
        }

        hideRulers();

        if (backlightManager != null) {
            backlightManager.cancel();
        }

        BroadcastHelper.sendAppInBackground(this, switchMode.isSelected());
        BroadcastHelper.sendAppIsHidden(this);
    }

    @Override
    public void onStop() {
        super.onStop();
        log("onStop");

        if(Props.getFlavorChipset().equals(Props.Flavor.Chipset.Optoma)){
            if(WbJniCall.isLoaded() && Props.getFlavorChipset().equals(Props.Flavor.Chipset.Optoma))
                WbJniCall.fbShowGop(false);
        }

        if(whiteboard.getState().isAnnotationState()  && Props.getFlavorChipset().equals(Props.Flavor.Chipset.Amlogic)) {
            Thread t = new Thread(new Runnable() {
                @Override
                public void run() {
                    Instrumentation instrumentation = new Instrumentation();
                    instrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_MEDIA_PLAY);
                }
            });
            t.start();
        }
        isOnCreateOrOnNewIntentCalled = false;

        if (switchMode != null && switchMode.isSelected()) {
            // app is stopping, set flag to not in annotation mode
            setHoldOnSourceFlag(false);
        }

        whiteboard.queueInput(InputEvent.createAction(InputEvent.Action.ON_STOP));

        boolean hasSystemSlept = SystemPropertiesUtils.getBooleanValue(SystemPropertiesUtils.KEY_HAS_SYSTEM_SLEPT, false);
        //19B，8386会将SystemPropertiesUtils.KEY_HAS_SYSTEM_SLEPT设为true，导致开机后resetApp函数中使用states出错
        if (Props.getFlavorModel().equals(Props.Flavor.Model.Oem) && Props.getFlavorChipset().equals(Props.Flavor.Chipset.Mstar)) {
            hasSystemSlept = false;
        }
        log("- hht.str.slept=" + hasSystemSlept);
        if (hasSystemSlept) {
            // TODO : RS PLUS firmware does not have 'KEY_HAS_SYSTEM_SLEPT' value.
            mSettings.setReloadWhiteboardJson(false);
            resetApp();
            finish();
            SystemPropertiesUtils.setValue(SystemPropertiesUtils.KEY_HAS_SYSTEM_SLEPT, false);
        } else {
            mSettings.setDetectAppClosedForcefully(true);
        }

        try {
            unregisterHhtActionBroadcastReceiver();
        } catch (Exception exception) {
            Log.d(TAG, "unregisterHhtActionBroadcastReceiver fail");
        }

        try {
//            unregisterEndMeetingReceiver();
        } catch (Exception exception) {
            Log.d(TAG, "unregisterEndMeetingReceiver fail");
        }

        // notify floatbar that app is stopping
        BroadcastHelper.sendAppIsHidden(this);

        /*by zf*/
        if (Props.getFlavorChipset().equals(Props.Flavor.Chipset.Optoma)) {
//            IsTouchManager.getInstance().setPublicUsbToTV(true, true);
//            IsTouchManager.getInstance().setTouchChannelUSB(curSourceTouchChannel, true);
//            Log.d("wjj", "(MT9666)KEYCODE_HOME onStop -> " + curSourceTouchChannel);
            IsTouchManager.getInstance().setTouchCmdConfig(7);
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        log("onDestroy");

        mSettings.setDetectAppClosedForcefully(false);

        mSettings.setReloadWhiteboardJson(false);

        InputManager.getInstance().reset();

        if (thread != null) {
            thread.setRunning(false);
        }

        if (fileHandlerThread != null) {
            fileHandlerThread.quitSafely();
        }

        if (jsonHandlerThread != null) {
            jsonHandlerThread.quitSafely();
        }

        if (fastDraw != null) {
            try {
                fastDraw.close();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        if (backlightManager != null) {
            backlightManager.close();
        }

        if (actionSound != null) {
            actionSound.release();
        }

        if (searchThumbnailsTask != null && !searchThumbnailsTask.isCancelled()) {
            if (browserCrawler != null) {
                browserCrawler.abortOkHttpRequest();
            }
            searchThumbnailsTask.cancel(true);
        }

        if (whiteboard != null) {
            final WhiteboardState state = whiteboard.getState();
            if (state != null && state.isAnnotationState()) {
                setExitOnAnnotationModeSystemProp();
            }
        }

        if (handler != null) {
            handler.removeCallbacksAndMessages(null);
        }

        try {
            APIManager.disconnectService(this);
        } catch (Exception e) {
            e.printStackTrace();
        }

        // reset the floatbar
        BroadcastHelper.sendAppIsHidden(this);

        if (FastDraw.isSupported() && mIDrawService != null) {
            unbindService(mConnection);
        }

        if (pool != null) {
            pool.shutdown();
        }

        if (restartApp) {
            restartApp = false;
            restartApp();
        }
        if (null != windowManager && null != floatingCursorView) {
            windowManager.removeView(floatingCursorView);
            floatingCursorView = null;
        }
        if (null != lastToast) {
            View toastView = lastToast.getView();
            toastView.setVisibility(GONE);
        }

        unRegisterHhtActionBroadcastOpenSplitMenuReceiver();
        unRegisterHhtActionBroadcastFloatingCursorReceiver();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        log("onActivityResult: requestCode=" + requestCode + ", resultCode=" + resultCode + ", data=" + data);
        requestCode = requestCode & 0x0000ffff;
        switch (requestCode) {
            case REQUEST_GET_IMAGE: {
                if (resultCode == RESULT_OK) {
                    final Uri contentUri = data.getData();
                    if (contentUri != null) {
                        whiteboard.queueInput(InputEvent.createAddImageAction(contentUri));
                        inputSelect.callOnClick();
                    }

                } else {
                    whiteboard.queueInput(InputEvent.createGetReadyForSelectionModeAction(Whiteboard.RESET_TEXT_SELECTION_AREA_ACTION));
                }
                break;
            }
            case REQUEST_GET_CUSTOM_BACKGROUND: {
                if (pageMenuView == null) {
                    initPageView();
                }
                if (resultCode == RESULT_OK) {
                    final Uri contentUri = data.getData();
                    if (contentUri != null) {
                        try {
                            final Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), contentUri);
                            if (bitmap != null) {
                                pageProp.setCustomBackground(getResources(), bitmap);
                                if (pageMenuView != null) {
                                    pageMenuView.clickOnOkay();

                                    pageProp.generateCustomBackgroundName(contentUri, getContentResolver());
                                }
//                                fileHandler.sendSaveImageToInternal(bitmap);
                            } else {
                                pageMenuView.resetPatternSelection();
                                showToast(getString(R.string.page_unsupported_custom_background));
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                            pageMenuView.resetPatternSelection();
                            showToast(getString(R.string.page_unsupported_custom_background));
                        }
                    }
                } else {
                    pageMenuView.resetPatternSelection();
                    showToast(getString(R.string.page_unsupported_custom_background));
                }
                break;
            }
        }
    }

    @Override
    public void onSelectionBoxBoundsChange(float left, float top, float right, float bottom) {
        if (selectionView != null) {
            runOnUiThread(() -> selectionView.setBoxBounds(left, top, right, bottom));
        }
    }

    @Override
    public void onSelectionBoxVisibleChange(boolean visible, int selectionRenderMode) {
        if (selectionView != null) {
            runOnUiThread(() -> {
                if (selectionView != null) {
                    if (visible) {
                        selectionView.show(selectionRenderMode);
                    } else {
                        selectionView.hide();
                    }
                    selectionView.requestLayout();
                }
            });
        }
    }

    @Override
    public void onSelectionBoxImageOnly(boolean imageOnly) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (selectionView != null) {
                    selectionView.setImageOnly(imageOnly);
                }
            }
        });
    }

    @Override
    public void onSelectionCopyClick() {
        whiteboard.queueInput(InputEvent.createAction(InputEvent.Action.COPY));
    }

    @Override
    public void onSelectionCutClick() {
        whiteboard.queueInput(InputEvent.createAction(InputEvent.Action.CUT));
    }

    @Override
    public void onSelectionDeleteClick() {
        whiteboard.queueInput(InputEvent.createAction(InputEvent.Action.DELETE));
    }


    @Override
    public void onColorChange(int color) {
        whiteboard.queueInput(InputEvent.create(InputEvent.Action.COLOR_CHANGED, color));
    }

    @Override
    public void onStickynoteColorChange(int color) {
        whiteboard.queueInput(InputEvent.create(InputEvent.Action.STICKYNOTE_COLOR_CHANGED, color));

    }

    @Override
    public void onTrimingClick() {
        hideMenus();
        whiteboard.queueInput(InputEvent.createAction(InputEvent.Action.TRIMING));
    }

    @Override
    public void onSelectionStickyNoteClick() {
        hideMenus();
        whiteboard.queueInput(InputEvent.createAction(InputEvent.Action.MAKE_STICKY_NOTE));
    }

    @Override
    public void onPushEndClick() {
        whiteboard.queueInput(InputEvent.createAction(InputEvent.Action.PUSH_END));
    }

    @Override
    public void onMenuClick() {
        hideMenus();
    }

    @Override
    public void onSetActiveWord(boolean visible, Word.Config config) {
        if (wordDelegate != null) {
            runOnUiThread(() -> {
                if (visible && config != null) {
                    wordDelegate.removeTextChangedListener(wordDelegateTextWatcher);

                    wordDelegate.setX(config.getX());
                    wordDelegate.setY(config.getY());
                    wordDelegate.setEdited(config.getEdited());

                    if (config.getWidth() > 0) {
                        wordDelegate.setWidth(config.getWidth());
                        // following line cause wordDelegate to be disabled from wrapping text when text has not resized.
//                    wordDelegate.setMaxWidth(config.getMaxWidth());
                        if (!config.isTextScaled() && config.getWidth() < wordDefaultWidth) {
                            wordDelegate.setMaxWidth(wordDefaultWidth);
                        } else {
                            wordDelegate.setMaxWidth(config.getMaxWidth());
                        }
                    }

                    wordDelegate.setRotation(config.getRotation());

                    wordDelegate.setText(config.getText());
                    wordDelegate.setTextSize(TypedValue.COMPLEX_UNIT_PX, config.getTextSize());
                    wordDelegate.setTextColor(config.getTextColor());

                    if (config.getHeight() > 0) {
                        wordDelegate.setHeight(config.getHeight());
                        wordDelegate.setMinHeight(config.getMinHeight());
                        wordDelegate.setMaxHeight(Integer.MAX_VALUE); // reset to default max value
                    }
                    ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) wordDelegate.getLayoutParams();

//                layoutParams.width = config.getLayoutWidth();
                    if (!config.isTextScaled() && config.getWidth() < wordDefaultWidth) {
                        layoutParams.width = ConstraintLayout.LayoutParams.WRAP_CONTENT;
                    } else {
                        layoutParams.width = config.getLayoutWidth();
                    }
                    layoutParams.height = config.getLayoutHeight();
                    wordDelegate.setLayoutParams(layoutParams);

                    wordDelegate.setBound(config.getBoundX(), config.getBoundY(), config.getBoundW(), config.getBoundH());

                    wordDelegate.addTextChangedListener(wordDelegateTextWatcher);

                    wordDelegate.setVisibility(View.VISIBLE);
                    wordDelegate.resetIsComposing();
                    wordDelegate.requestFocus();
                    wordDelegate.invalidate();
                    wordDelegate.requestLayout();

                    InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
                    if (imm != null) {
                        imm.showSoftInput(wordDelegate, 0);
                    }
                } else {
                    hideWordDelegate();
                }
            });
        }
    }

    private void hideWordDelegate() {
        if (wordDelegate != null && (wordDelegate.getVisibility() != View.INVISIBLE || wordDelegate.isFocused())) {
            wordDelegate.setVisibility(View.INVISIBLE);

            wordDelegate.clearFocus();

            InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
            if (imm != null) {
                imm.hideSoftInputFromWindow(wordDelegate.getWindowToken(), 0);
            }
        }
    }

    @Override
    public void setCursor(int cur) {
        if (wordDelegate != null) {
            runOnUiThread(() -> {
                if (cur >= 0 && cur <= wordDelegate.getText().length()) {
                    wordDelegate.setCursor(cur);
                }
            });
        }
    }

    @Override
    public void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        log("onNewIntent");
        Log.d("wjj", "onNewIntent");

        setIntent(intent);

        Log.d("wjj", "- isFinishing=" + isFinishing);
        if (isFinishing) {
            BroadcastHelper.sendScreenshotEndAndAppIsFinishing(this);
            return;
        }

        isOnCreateOrOnNewIntentCalled = true;

        if (intent.getBooleanExtra(EXTRA_END_MEETING, false)) {
            Log.d("wjj", "- EXTRA_END_MEETING=true");

            isFinishing = true;
            finish();
            return;
        }

        if (intent.getBooleanExtra(EXTRA_HIDE_APP, false)) {
            Log.d("wjj", "- EXTRA_HIDE_APP=true");

            onNewIntentHideApp();
            return;
        }

        if (intent.getBooleanExtra(EXTRA_ANNOTATION_MODE, false)) {
            Log.d("wjj", "- EXTRA_ANNOTATION_MODE=true");

            if (whiteboard.getState().isAnnotationState() && isActivityVisible) {
                onNewIntentHideApp();
            } else {
                onNewIntentAnnotationMode();
            }
        } else {
            Log.d("wjj", "- EXTRA_ANNOTATION_MODE=false");
            if (toggleBar != null && toggleBar.isSelected()) {
                toggleBar.callOnClick();
            }

            if (switchMode != null && switchMode.isSelected()) {
                switchMode.callOnClick();
            }

            if (navigatorView != null && navigatorView.isVisible()) {
                navigatorView.hide();
            }

            if (exitWhiteboard != null && exitWhiteboard.getVisibility() == GONE) {
                exitWhiteboard.setVisibility(View.VISIBLE);
            }

            //add by jay
            Uri shortPathUri = intent.getData();
            if(shortPathUri != null){
                Log.d("jay","---onNewIntent---shortPathUri=" + shortPathUri.getPath());
                String type = intent.getType();
                Log.d("jay","---onNewIntent---type=" + type);
                if(!TextUtils.isEmpty(type)){
                    if(type.equals("image/*")){
                        String path = shortPathUri.getPath();
                        Log.d("jay","---onNewIntent---inputPath=" + path);
                        if(!TextUtils.isEmpty(path)){
                            getFilePathFromIntent(path);
                        }
                    }
                }
            }
            //end

            String intentFilePath = intent.getStringExtra(FileHelper.FILE_PATH);
            if (intentFilePath != null && !intentFilePath.isEmpty()) {
                getFilePathFromIntent(intentFilePath);
            } else if (intent.getParcelableExtra("rect") != null) {
                getImageRectFromIntent(intent);
            }
            if (null != floatingCursorView)
                floatingCursorView.setVisibility(GONE);

            setExitSplitMenu(intent.hasExtra(EXIT_SPLIT_MENU) ? intent.getBooleanExtra(EXIT_SPLIT_MENU, true) : isExitSplitMenu());
        }

    }

    private void getFilePathFromIntent(String path) {
        if (handler == null) {
            handler = new Handler();
        }
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                File file = new File(path);
                if (file.exists()) {
                    BitmapFactory.Options options = new BitmapFactory.Options();
                    options.inPreferredConfig = Bitmap.Config.ARGB_8888;
                    Bitmap screenShot = BitmapFactory.decodeFile(path, options);
                    if (screenShot != null) {
                        whiteboard.queueInput(InputEvent.createAddImageAction(screenShot));
                        inputSelect.callOnClick();
                        log("getFilePathFromIntent : success");
                    } else {
                        log("getFilePathFromIntent : bitmap is null");
                    }
                } else {
                    log("getFilePathFromIntent : path is invalid, path : " + path);
                }
            }
        }, 160);
    }

    private void getImageRectFromIntent(Intent intent) {
        if (handler == null) {
            handler = new Handler();
        }
        handler.post(new Runnable() {
            @Override
            public void run() {
                final View decor = getWindow().getDecorView();
                // final Bitmap screenshot = SurfaceControlUtils.takeScreenshot(decor.getWidth(), decor.getHeight());
                final Bitmap screenshot = SurfaceControlUtils.startScreenShot(decor.getWidth(), decor.getHeight());
                Rect rect = intent.getParcelableExtra("rect");
                int left = rect.left;
                int top = rect.top;
                int right = rect.right;
                int bottom = rect.bottom;

                if (screenshot != null && left >= 0 && top >= 0 && right > 0 && bottom > 0) {
                    Bitmap resizedBitmap = Bitmap.createBitmap(screenshot, left, top, Math.abs(right - left), Math.abs(top - bottom));

                    if (resizedBitmap != null) {
                        whiteboard.queueInput(InputEvent.createAddImageAction(resizedBitmap));
                        inputSelect.callOnClick();
                    } else {
                        whiteboard.queueInput(InputEvent.createGetReadyForSelectionModeAction(Whiteboard.RESET_TEXT_SELECTION_AREA_ACTION));
                    }
                }
            }
        });
    }

    private void onNewIntentHideApp() {
        if (toggleControl != null && toggleControl.isSelected()) {
//            Intent intent = new Intent(DisplayControlImpl.USBTOUCH_ENABLE);
//            displayControl.setIntent(intent);
            displayControlNChina.enableUsbTouch(this);
            displayControl.stop(this);
            log("displayControl : onNewIntentHideApp : " + DisplayControlImpl.USBTOUCH_ENABLE);
        }

        if (whiteboard.getState().isAnnotationState() && isAutoScreenshotEnabled) {
            isFinishing = true;
            takeScreenshot(hideAfterAnimationListener);
        } else {
            // X9 will hide floatbar automatically when broadcasting the quit app intent.  Send
            // a broadcast to make floatbar visible again.
            BroadcastHelper.sendScreenshotEndAndAppIsFinishing(this);
            moveTaskToBack(true);
        }
    }

    private void onNewIntentAnnotationMode() {
        if (toggleControl != null) {
            if (!Props.getFlavorModel().equals(Props.Flavor.Model.Wcd) && displayControl.isSupported(this)) {
                toggleControl.setVisibility(View.VISIBLE);
            } else {
                if (toggleControl.isSelected()) {
                    toggleControl.callOnClick();
                }
                if (!Props.getFlavorModel().equals(Props.Flavor.Model.Wcd)) {
                    toggleControl.setVisibility(View.GONE);
                }
            }
        }

        if (toggleBar != null && toggleBar.isSelected()) {
            toggleBar.callOnClick();
        }

        if (switchMode != null && !switchMode.isSelected()) {
            switchMode.callOnClick();
        }

        if (navigatorView != null && navigatorView.isVisible()) {
            navigatorView.hide();
        }

        if (exitWhiteboard != null && exitWhiteboard.getVisibility() == View.VISIBLE) {
            exitWhiteboard.setVisibility(GONE);
        }

    }

    @Override
    public void onBackPressed() {
        final long currentTime = System.currentTimeMillis();
        if (currentTime - lastBackPressTime > backPressConfirmInterval) {
            showToast(getString(R.string.back_press_confirm_exit));
            lastBackPressTime = currentTime;
        } else {
            if (isFinishing) {
                // do nothing
                return;
            }
            if (null != floatingCursorView && View.VISIBLE == floatingCursorView.getVisibility() && null != floatingCursorFloatingCursorView
                    && whiteboard.getState().isAnnotationState() && isAutoScreenshotEnabled)//19B，批注模式、Android鼠标模式下设置返回退出时截图
                floatingCursorFloatingCursorView.performClick();
            if (lastToast != null) {
                View toastView = lastToast.getView();
                toastView.setVisibility(GONE);
            }
            isFinishing = true;
            cancelFastDraw();
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {

                    if (whiteboard.getState().isAnnotationState() && isAutoScreenshotEnabled) {


                        if (toggleControl != null && toggleControl.isSelected()) {
                            toggleControl.callOnClick();
                        }

                        takeScreenshot(finishAfterAnimationListener);
                    } else {
                        MainActivity.super.onBackPressed();
                    }
                }
            }, 500);

        }
    }

    @Override
    public void createImage(String thumbnailUrl, String sourceUrl, float x, float y) {
        if (inputSelect != null) {
            toggleInput(inputSelect);
            setDeviceInput(Device.FINGER, inputSelect);
        }
        downloadImage(thumbnailUrl, sourceUrl, x, y);

    }

    //
    private void downloadImage(String thumbnailUrl, String sourceUrl, float x, float y) {
        // TOdO : customize the timeout correctly
        if (whiteboard == null) {
            return;
        } else if (((thumbnailUrl == null || thumbnailUrl.isEmpty()) && (sourceUrl == null || sourceUrl.isEmpty()))) {
            disableImageSearchTouchBlock();
            return;
        }

        int width = whiteboard.getWidth();
        int height = whiteboard.getHeight();

        RequestListener<Bitmap> thumbnailRequestListener = new RequestListener<Bitmap>() {
            @Override
            public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Bitmap> target, boolean isFirstResource) {
                disableImageSearchTouchBlock();
                return true;
            }

            @Override
            public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) {
                // Use empty url to skip the process of downloading the source image in whiteboard.
                whiteboard.queueInput(InputEvent.createAddImageBySearchingAction(thumbnailUrl, x, y));
                return true;
            }
        };

        RequestListener<Bitmap> sourceRequestListener = new RequestListener<Bitmap>() {
            @Override
            public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Bitmap> target, boolean isFirstResource) {
                Target thumbnailTarget = GlideApp.with(MainActivity.this.getApplicationContext())
                        .asBitmap()
                        .downsample(DownsampleStrategy.CENTER_INSIDE)
                        .listener(thumbnailRequestListener)
                        .load(thumbnailUrl)
//                        .timeout(10000)
                        .submit((int) (width * 0.75f), (int) (height * 0.75f));

//                targetList.add(target);
                targetList.add(thumbnailTarget);

                return true;
            }

            @Override
            public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) {
//                whiteboard.queueInput(InputEvent.createAddImageBySearchingAction(thumbnailUrl, sourceUrl, x, y));
                whiteboard.queueInput(InputEvent.createAddImageBySearchingAction(sourceUrl, x, y));
                return true;
            }
        };

        // download image from source url.
        Target target = GlideApp.with(this.getApplicationContext())
                .asBitmap()
                .downsample(DownsampleStrategy.CENTER_INSIDE)
                .listener(sourceRequestListener)
                .load(sourceUrl)
                //                .timeout(10000)
                .submit((int) (width * 0.75f), (int) (height * 0.75f));

        targetList.add(target);

    }

    @Override
    public void disableImageSearchTouchBlock() {
        runOnUiThread(() -> {
            if (searchImageView != null) {
                searchImageView.setTouchBlock(false);
            }
        });
    }

    @Override
    public void getImageSet(List<String> dataSet, String searchTerm) {
//        new SearchThumbnailsTask().execute(searchTerm);
        if (isNetworkConnected()) {
            searchThumbnailsTask = new SearchThumbnailsTask();
            if (searchTerm != null) {
                searchThumbnailsTask.execute(searchTerm);
            }
        } else {
            if (searchImageView != null) {
                // unlock view
                String errMsg = "Unknown error";
                if (browserCrawler != null && !browserCrawler.getErrorMsg().isEmpty()) {
                    errMsg = browserCrawler.getErrorMsg();
                }
                searchImageView.updateSearchResult(null, null, null, errMsg);
            }
        }
    }

    class SearchThumbnailsTask extends AsyncTask<String, Void, Void> {

        @Override
        protected Void doInBackground(String... strings) {
            try {
                Glide.get(MainActivity.this).clearDiskCache();
                if (!isCancelled()) {
                    browserCrawler.searchSrcUrls(strings[strings.length - 1]);
                }
                return null;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);
            if (searchImageView != null) {
                searchImageView.updateSearchResult(browserCrawler.getThumbnailsUrl(), browserCrawler.getSourceUrl(), browserCrawler.getImageSize(),
                        browserCrawler.getErrorMsg());
            }
        }

        @Override
        protected void onCancelled(Void aVoid) {
//            super.onCancelled(aVoid);
            if (searchImageView != null && browserCrawler != null) {
                // unlock view
                String errmsg = browserCrawler.getErrorMsg();
                searchImageView.updateSearchResult(null, null, null, errmsg);
            }
        }

    }

    @Override
    public void cancelSearchTask() {
//        if (browserCrawler!=null) {
//            browserCrawler.abortHttpRequest();
//        }
        if (searchThumbnailsTask != null) {
            if (browserCrawler != null) {
                browserCrawler.abortOkHttpRequest();
            }
            searchThumbnailsTask.cancel(true);
        }

        if (targetList != null && !targetList.isEmpty()) {
            for (Target target : targetList) {
                Glide.with(this.getApplicationContext()).clear(target);
            }
            targetList.clear();
        }

        if (searchImageView != null && browserCrawler != null) {
            // unlock view
            String errmsg = browserCrawler.getErrorMsg();
            searchImageView.updateSearchResult(null, null, null, errmsg);
        }

    }

    @Override
    public void cancelSearchTaskAfterAddImage() {
//        Glide.with(this.getApplicationContext()).clear(targetMainActivity);
//        targetList.remove(targetMainActivity);
        if (targetList.size() > 0) {
            for (Target target : targetList) {
                Glide.with(this.getApplicationContext()).clear(target);
            }
            targetList.clear();
        }
    }

    @Override
    public void triggerAddImage(View v) {
        if (imageToolbarMenuView == null) {
            initImageToolbarMenuView();
        }
        imageToolbarMenuView.setVisibility(View.GONE);

        whiteboard.queueInput(InputEvent.createGetReadyForSelectionModeAction(Whiteboard.CLEAR_TEXT_SELECTION_AREA_ACTION));

        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.setType("image/*");
        intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[]{"image/jpeg", "image/png", "image/bmp", "image/gif"});
        if (intent.resolveActivity(getPackageManager()) != null) {
            startActivityForResult(intent, REQUEST_GET_IMAGE);
        }

        hideMenus();

    }

    @Override
    public void triggerImageSearch(View v) {
        if (searchImageView != null) {
            if (searchImageView.getVisibility() != View.VISIBLE) {
                searchImageView.setVisibility(View.VISIBLE);
                whiteboard.queueInput(InputEvent.createGetReadyForSelectionModeAction(Whiteboard.CLEAR_TEXT_SELECTION_AREA_ACTION));
            } else {
                searchImageView.setVisibility(View.GONE);
                whiteboard.queueInput(InputEvent.createGetReadyForSelectionModeAction(Whiteboard.RESET_TEXT_SELECTION_AREA_ACTION));
            }

            searchImageView.toggleWebView(searchImageView.getVisibility() == View.VISIBLE);
        }

        if (imageToolbarMenuView == null) {
            initImageToolbarMenuView();
        }
        imageToolbarMenuView.setVisibility(View.GONE);
    }

    @Override
    public void triggerWebTrimming(View v) {
        final Intent intent = new Intent();
        intent.setClassName(getString(R.string.package_web_image), getString(R.string.activity_web_image));
//        intent.putExtra("use_result",true);

        final List<ResolveInfo> activities = getPackageManager().queryIntentActivities(intent,
                PackageManager.MATCH_DEFAULT_ONLY);
        if (activities.size() > 0) {
            startActivity(intent);
            overridePendingTransition(0, 0);

            whiteboard.queueInput(InputEvent.createGetReadyForSelectionModeAction(Whiteboard.CLEAR_TEXT_SELECTION_AREA_ACTION));
        } else {
            Log.e(TAG, "Web image app not installed!");
        }

        if (imageToolbarMenuView == null) {
            initImageToolbarMenuView();
        }
        imageToolbarMenuView.setVisibility(View.GONE);
    }

    @Override
    public void triggerYoutubeVideo(View v) {
        if (youtubeSearchView != null) {
            if (youtubeSearchView.getVisibility() != View.VISIBLE) {
                youtubeSearchView.setVisibility(View.VISIBLE);
                whiteboard.queueInput(InputEvent.createGetReadyForSelectionModeAction(Whiteboard.CLEAR_TEXT_SELECTION_AREA_ACTION));
            } else {
                youtubeSearchView.setVisibility(GONE);
                whiteboard.queueInput(InputEvent.createGetReadyForSelectionModeAction(Whiteboard.RESET_TEXT_SELECTION_AREA_ACTION));
            }
            youtubeSearchView.toggleWebView(youtubeSearchView.getVisibility() == View.VISIBLE);
        }
        if (imageToolbarMenuView == null) {
            initImageToolbarMenuView();
        }
        imageToolbarMenuView.setVisibility(View.GONE);
    }

    public YoutubeSearchView getYoutubeSearchView() {
        return youtubeSearchView;
    }

    public static void hookWebView() {
        int sdkInt = Build.VERSION.SDK_INT;
        try {
            Class<?> factoryClass = Class.forName("android.webkit.WebViewFactory");
            Field field = factoryClass.getDeclaredField("sProviderInstance");
            field.setAccessible(true);
            Object sProviderInstance = field.get(null);
            if (sProviderInstance != null) {
                Log.i(TAG, "sProviderInstance isn't null");
                return;
            }

            Method getProviderClassMethod;
            if (sdkInt > 22) {
                getProviderClassMethod = factoryClass.getDeclaredMethod("getProviderClass");
            } else if (sdkInt == 22) {
                getProviderClassMethod = factoryClass.getDeclaredMethod("getFactoryClass");
            } else {
                Log.i(TAG, "Don't need to Hook WebView");
                return;
            }
            getProviderClassMethod.setAccessible(true);
            Class<?> factoryProviderClass = (Class<?>) getProviderClassMethod.invoke(factoryClass);
            Class<?> delegateClass = Class.forName("android.webkit.WebViewDelegate");
            Constructor<?> delegateConstructor = delegateClass.getDeclaredConstructor();
            delegateConstructor.setAccessible(true);
            if (sdkInt < 26) {
                Constructor<?> providerConstructor = factoryProviderClass.getConstructor(delegateClass);
                if (providerConstructor != null) {
                    providerConstructor.setAccessible(true);
                    sProviderInstance = providerConstructor.newInstance(delegateConstructor.newInstance());
                }
            } else {
                Field chromiumMethodName = factoryClass.getDeclaredField("CHROMIUM_WEBVIEW_FACTORY_METHOD");
                chromiumMethodName.setAccessible(true);
                String chromiumMethodNameStr = (String) chromiumMethodName.get(null);
                if (chromiumMethodNameStr == null) {
                    chromiumMethodNameStr = "create";
                }
                Method staticFactory = factoryProviderClass.getMethod(chromiumMethodNameStr, delegateClass);
                if (staticFactory != null) {
                    sProviderInstance = staticFactory.invoke(null, delegateConstructor.newInstance());
                }
            }

            if (sProviderInstance != null) {
                field.set("sProviderInstance", sProviderInstance);
                Log.i(TAG, "Hook success!");
            } else {
                Log.i(TAG, "Hook failed!");
            }
        } catch (Throwable e) {
            Log.w(TAG, e);
        }
    }

    /**
     * Checks display device settings.
     */
//    private void checkDisplaySettings() {
//        isWritingEyeProtectionEnabled = displayManager.isWritingEyeProtectionEnabled(this);
//    }
    private void checkDisplaySettings() {
//        isWritingEyeProtectionEnabled = displayManager.isWritingEyeProtectionEnabled(this);
//        if (HHTCommand.getInstance(this).getBooleanValue("write_protection")){
//            isWritingEyeProtectionEnabled = true;
//        }
//        else{
//            isWritingEyeProtectionEnabled = false;
//        }

        if (Props.getFlavorChipset().equals(Props.Flavor.Chipset.Mstar)) {
            if (displayManager.isWritingEyeProtectionEnabled(this)) {
                isWritingEyeProtectionEnabled = true;
            } else {
                isWritingEyeProtectionEnabled = false;
            }
            //isWritingEyeProtectionEnabled = displayManager.isWritingEyeProtectionEnabled(this);
        } else if (Props.getFlavorChipset().equals(Props.Flavor.Chipset.Hisi)) {
            //            android.provider.Settings.System.putInt(getContentResolver(), "hold_on_source_flag", isAnnotationMode ? 1 : 0);
            // 1 is on, 0 is off
            int isEnable = android.provider.Settings.System.getInt(getApplicationContext().getContentResolver(), "key_eye_protection", 0);
            if (/*IstEventManager.getInstance().isBacklightEnable() &&*/ isEnable == 1) {
                isWritingEyeProtectionEnabled = true;
            } else {
                isWritingEyeProtectionEnabled = false;
            }
        } else if (Props.getFlavorChipset().equals(Props.Flavor.Chipset.Amlogic)) {
            HHTCommand hhtCommand = HHTCommand.getInstance(this);
            hhtCommand.init();
            String temp = hhtCommand.getValueByCommand("write_protection");
            if (temp != null) {
                if (temp.equals("on")) {
                    isWritingEyeProtectionEnabled = true;
                } else {
                    isWritingEyeProtectionEnabled = false;
                }
            } else {
                Log.d("debug", "test write_protection is null ");
            }
        }else if (Props.getFlavorChipset().equals(Props.Flavor.Chipset.Optoma)){
            String result = android.provider.Settings.System.getString(getContentResolver(), "write_protection");
            if (result!=null && result.split(":")[1].contains("on")){
                Log.d("debug","test write_protection true");
                isWritingEyeProtectionEnabled = true;
            }else
                Log.d("debug","test write_protection false");
            Log.d("debug","test write_protection is"+ result);
        }
    }

    private void shareFile(String file) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            final Intent intent = FileShareUtils.createShareIntent(this, file);
            if (intent != null) {
                startShare(intent);
            } else {
                Log.e(TAG, "Sharer app not installed!");
            }
        } else {
            final String fileProvider = getString(R.string.file_provider);
            final Uri uri = FileProvider.getUriForFile(this, fileProvider, new File(file));

            final Intent intent = new Intent();
            intent.setAction(Intent.ACTION_SEND);
            intent.putExtra(Intent.EXTRA_STREAM, uri);
            intent.setType("image/png");
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            startActivity(Intent.createChooser(intent, getString(R.string.share_title)));
        }
    }

    private void setBottomBarButtonsEnable(boolean enable) {
        if (switchMode != null) {
            switchMode.setEnabled(enable);
        }
        if (inputText != null) {
            inputText.setEnabled(enable);
        }
        if (inputAutoshape != null) {
            inputAutoshape.setEnabled(enable);
        }
        inputPen.setEnabled(enable);
        inputHighlighter.setEnabled(enable);
        if (inputSelect != null) {
            inputSelect.setEnabled(enable);
        }
        inputEraser.setEnabled(enable);
        clearAll.setEnabled(enable);
        undo.setEnabled(enable);
        if (redo != null) {
            redo.setEnabled(enable);
        }
        if (addPage != null) {
            addPage.setEnabled(enable);
        }
        if (backPage != null) {
            backPage.setEnabled(enable);
        }
        if (nextPage != null) {
            nextPage.setEnabled(enable);
        }
        if (navigator != null) {
            navigator.setEnabled(enable);
        }
        if (toggleBar != null) {
            toggleBar.setEnabled(enable);
        }
        if (toggleControl != null) {
            toggleControl.setEnabled(enable);
        }
        if (inputMoveCanvas != null) {
            inputMoveCanvas.setEnabled(enable);
        }
        takeScreenshot.setEnabled(enable);
    }

    public void showToast(String msg) {
        if (lastToast != null) {
            lastToast.cancel();
        }
        Toast toast = Toast.makeText(this, msg, Toast.LENGTH_SHORT);
//        lastToast = Toast.makeText(this, msg, Toast.LENGTH_SHORT);
        toastBackground = toast.getView();
        toastBackground.getBackground().setColorFilter(getResources().getColor(R.color.toast_background), PorterDuff.Mode.SRC_IN);
//        lastToast.show();
        if (mSettings.isFake4k()) {

            if (windowManager == null) {
                windowManager = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
            } else if (null != lastToast) {
                lastToast.getView().clearAnimation();
                windowManager.removeView(lastToast.getView());
            }

            if (windowMangerParams == null) {
                windowMangerParams = new WindowManager.LayoutParams();
                windowMangerParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
                windowMangerParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
                windowMangerParams.format = PixelFormat.TRANSLUCENT;
                windowMangerParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
                windowMangerParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
            }

            View toastView = toast.getView();
            toastView.measure(0, 0);
            Point point = new Point();
            windowManager.getDefaultDisplay().getSize(point);
//            windowMangerParams.x = (int) (-point.x * 0.5f + toastView.getMeasuredWidth() * 0.25f);
//            windowMangerParams.y = (int) (-point.y * 0.091f);
            windowMangerParams.y = 850;
            windowManager.addView(toastView, windowMangerParams);
            toastView.setAlpha(0f);
            toastView.animate()
                    .alpha(1f)
                    .setDuration(500)
                    .setListener(new AnimatorListenerAdapter() {
                        @Override
                        public void onAnimationEnd(Animator animation, boolean isReverse) {
                            toastView.setAlpha(1.0f);
                        }
                    });
            handler.postDelayed(() -> {
                toastView.setAlpha(1.0f);
                toastView.animate()
                        .alpha(0f)
                        .setDuration(1000)
                        .setListener(new AnimatorListenerAdapter() {
                            @Override
                            public void onAnimationEnd(Animator animation) {
                                toastView.setVisibility(GONE);
                            }
                        });
            }, 1500);
        } else {
            toast.show();
        }
        lastToast = toast;
    }

    private void shareScreenshot() {
        if (lastScreenshotFileName == null) {
            return;
        }

        final FileHelper fileHelper = FileHelper.getInstance(this);
        final File file = fileHelper.getPreviewFile(lastScreenshotFileName);
        if (!file.exists()) {
            return;
        }

        shareFile(file.toString());
    }

    /**
     * https://stackoverflow.com/questions/4238921/detect-whether-there-is-an-internet-connection-available-on-android
     */
    private boolean isNetworkConnected() {
        boolean haveConnectedWifi = false;
        boolean haveConnectedMobile = false;
        boolean wiredNetworkConnected;
        boolean wifiConnected;
        boolean netWorkConnected;

        ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo activeNetworkInfo = cm.getActiveNetworkInfo();

        // activeNetworkInfo can only detect network connection when wifi is not connected.
        // If wifi is connected, it is always true.
        wiredNetworkConnected = activeNetworkInfo != null && activeNetworkInfo.isConnected();

        NetworkInfo[] netInfo = cm.getAllNetworkInfo();
        for (NetworkInfo ni : netInfo) {
            if (ni.getTypeName().equalsIgnoreCase("WIFI")) {
                if (ni.isConnected()) {
                    haveConnectedWifi = true;
                }
            }
            if (ni.getTypeName().equalsIgnoreCase("MOBILE")) {
                if (ni.isConnected()) {
                    haveConnectedMobile = true;
                }
            }
        }
        wifiConnected = haveConnectedWifi || haveConnectedMobile;

        netWorkConnected = wiredNetworkConnected || wifiConnected;

        if (!netWorkConnected && browserCrawler != null) {
            String errMsg = BrowserCrawler.DISCONNECTION_ERRMSG;
            browserCrawler.setErrorMsg(errMsg);

            // debug
//            String debugMsg = ("wifi : " + wifiConnected + ", wired network : " + wiredNetworkConnected);
//            errMsg += debugMsg;
//            log(errMsg);
        }

        return netWorkConnected;

    }

    private void registerNavigatorBroadcastReceiver() {
        if (navigatorView != null) {
            IntentFilter filters = new IntentFilter();
            filters.addAction(getString(R.string.broadcast_action_media_eject));
            filters.addAction(getString(R.string.broadcast_action_media_mounted));
            filters.addDataScheme("file");

            registerReceiver(navigatorView.getBroadcastReceiver(), filters);
        }
    }

    private void unregisterNavigatorBroadcastReceiver() {
        if (navigatorView != null) {
            try {
                unregisterReceiver(navigatorView.getBroadcastReceiver());
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            }
        }
    }

    private void registerHhtActionBroadcastReceiver() {
        IntentFilter filters = new IntentFilter();
        filters.addAction(getString(R.string.broadcast_action_two_finger));
        filters.addAction(getString(R.string.broadcast_action_two_finger_311d));
        filters.addAction(getString(R.string.broadcast_action_transparent));
        filters.addAction("com.hht.action.exit.screenshot");
        registerReceiver(hhtActionBroadcastReceiver, filters);
    }

    private void unregisterHhtActionBroadcastReceiver() {
        unregisterReceiver(hhtActionBroadcastReceiver);
    }

    /**
     * 19C 白板分屏模式下回主页后再进入白板会退出分屏模式
     */
    private void registerHhtActionBroadcastOpenSplitMenuReceiver() {
        if (!Props.getFlavorModel().equals(Props.Flavor.Model.Oem) || !Props.getFlavorChipset().equals(Props.Flavor.Chipset.Hisi))
            return;
        IntentFilter filters = new IntentFilter();
        filters.addAction(getString(R.string.broadcast_action_exit_open_split_mode));
        registerReceiver(hhtActionBroadcastSplitMenuReceiver, filters);
    }

    private void unRegisterHhtActionBroadcastOpenSplitMenuReceiver() {
        if (Props.getFlavorModel().equals(Props.Flavor.Model.Oem) && Props.getFlavorChipset().equals(Props.Flavor.Chipset.Hisi)) {
            try {
                unregisterReceiver(hhtActionBroadcastSplitMenuReceiver);
            }catch (IllegalArgumentException e){
                e.printStackTrace();
            }
        }
    }

    /**
     * 19B 悬浮窗监听home键
     */
    private void registerHhtActionBroadcastFloatingCursorReceiver() {
        if (!Props.getFlavorModel().equals(Props.Flavor.Model.Oem) || !Props.getFlavorChipset().equals(Props.Flavor.Chipset.Mstar))
            return;
        IntentFilter filters = new IntentFilter();
        filters.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
        registerReceiver(hhtActionBroadcastFloatingCursorReceiver, filters);
    }

    private void unRegisterHhtActionBroadcastFloatingCursorReceiver() {
        if (Props.getFlavorModel().equals(Props.Flavor.Model.Oem) && Props.getFlavorChipset().equals(Props.Flavor.Chipset.Mstar))
            unregisterReceiver(hhtActionBroadcastFloatingCursorReceiver);
    }

    private final HhtActionBroadcastReceiver.Listener hhtActionListener = new HhtActionBroadcastReceiver.Listener() {
        @Override
        public void onTwoFingerGesture() {
            log("onTwoFingerGesture");
            whiteboard.getKeyFrameBufferLockOffAppWriteActionMoveCache().clear();
            isInTouchGesture = true;

            cancelFastDraw();
            whiteboard.queueInput(InputEvent.createRemoveActiveItemsAction(false));
        }

        @Override
        public void notifySurfaceClear() {
            whiteboard.clearWhiteBoard(true);
        }

        @Override
        public void setExitSplitMenuState(boolean flag) {
            setExitSplitMenu(flag);
        }

        @Override
        public void dealWithActionCloseSystemDialogs() {
            floatingCursorView.setVisibility(GONE);
        }
        @Override
        public void notifyScreenShotExit() {
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    IsTouchManager.getInstance().setTouchCmdConfig(8);
                }
            }, 300);
        }
    };

    private void registerEndMeetingReceiver() {
        IntentFilter filters = new IntentFilter();
        filters.addAction(getString(R.string.broadcast_action_end_meeting));
        registerReceiver(endMeetingReceiver, filters);
    }

    private void unregisterEndMeetingReceiver() {
        unregisterReceiver(endMeetingReceiver);
    }

    private final BroadcastReceiver endMeetingReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            isFinishing = true;
            finish();
        }
    };

    private void setHoldOnSourceFlag(boolean isAnnotationMode) {
        // setting this flag is required for RS builds
        // 1: in annotation mode
        // 0: not in annotation mode
        try {
            android.provider.Settings.System.putInt(getContentResolver(), "hold_on_source_flag", isAnnotationMode ? 1 : 0);
        } catch (SecurityException e) {
            e.printStackTrace();
        }
    }

    private boolean checkIf_U_TypeTouch() {

        //if the touch solution is FlatFrog touch, return false
        String fftouchret = SystemPropertiesUtils.getStringValue(SystemPropertiesUtils.KEY_IS_FF_TOUCH, "others");
        if (fftouchret.compareTo("others") != 0) {
            log("system properties persist.hht.xseria is true.");
            return false;
        }
        log("system properties persist.hht.xseria is false.");

        File fileR = new File(Environment.getRootDirectory() + "/../dev/ttyUSB0");
        if (fileR.exists()) {
            log("tty exist U.");
            return true;
        } else {
            log("tty not exist X.");
            return false;
        }
    }

    @Override
    public void showQRCode(String url) {
        runOnUiThread(() -> {
            if (qrCodeDialog != null) {
                if (!isNetworkConnected()) {
                    qrCodeDialog.setVisibility(View.GONE);
                    String networkErrorMsg = MainActivity.this.getResources().getString(R.string.qr_code_network_error_msg);
                    showToast(networkErrorMsg);
                    return;
                }
                qrCodeDialog.setVisibility(View.VISIBLE);
                if (url != null) {
                    Bitmap qrBitmap = QRCode.from(url).bitmap();
                    qrCodeDialog.setQrCodeView(qrBitmap);
                } else {
                    qrCodeDialog.setQrCodeView(null);
                }
            }
        });
    }

    @Override
    public void onExportClicked(List<Item> selected) {
        NavigatorViewQRCodeDownloadDialog downloadDialog = new NavigatorViewQRCodeDownloadDialog(MainActivity.this, handler);
        exportDialog = new NavigatorViewQRCodeExportDialog(MainActivity.this, states, downloadDialog, selected);

        exportDialog.show();
    }

    @Override
    public void onShareClicked(Intent intent) {
        startShare(intent);
    }

    public void startShare(Intent intent) {
        startActivity(intent);
    }

    public boolean isMoveCanvasSelected() {
        return (inputMoveCanvas != null && inputMoveCanvas.isSelected());
    }

    @Override
    public boolean isLongPressing() {
        return isInTouchGesture;
    }


    private void doRestartApp() {
        restartApp = true;
        MainActivity.this.finish();
    }

    private void restartApp() {
//        Intent i = getBaseContext().getPackageManager()
//                .getLaunchIntentForPackage(getBaseContext().getPackageName());
//        assert i != null;
//        i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK);
//        if (whiteboard != null && whiteboard.getState() != null) {
//            i.putExtra(MainActivity.EXTRA_ANNOTATION_MODE, whiteboard.getState().isAnnotationState());
//        }
//        startActivity(i);

        Intent intent = new Intent(getApplicationContext(), MainActivity.class);
        int mPendingIntentId = 35504768;
        PendingIntent mPendingIntent = PendingIntent.getActivity(getApplicationContext(), mPendingIntentId, intent, PendingIntent.FLAG_CANCEL_CURRENT);
        AlarmManager mgr = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
        mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 500, mPendingIntent);
        System.exit(0);
    }

    private void setRenderThreadFutureTask() {
        final int initDelay = 8000;
        final int checkPeriod = 8000;

        pool = Executors.newScheduledThreadPool(1);
        pool.scheduleAtFixedRate(() -> {
            log("lockCanvasTest scheduleAtFixedRate : " + System.currentTimeMillis() + ", thread != null ? " + (thread != null) +
                    ", is rendering ? " + (thread == null ? "null" : thread.isRendering()));
            if (thread != null && thread.isRendering()) {
                long currentTime = System.currentTimeMillis();
                long renderStart = thread.getStartRecord();
                log("lockCanvasTest setRenderThreadFutureTask : " + currentTime);

                // the thread is blocked by lockCanvas
                if (thread.isLocked() && currentTime - renderStart > checkPeriod && renderStart != 0) {
                    log("lockCanvasTest Timer : Thread is stopped when lockCanvas(), current : " + currentTime + ", render start : " + renderStart +
                            ", lock time : " + (currentTime - renderStart));

                    pool.shutdown();
                    pool = null;

                    // TODO : restart app when detect lockCanvas error
//                    recoverWB();
                    isCleanBufferRequired = true;
                    cancelFastDraw();
                    isCleanBufferRequired = false;
                    mSettings.setReloadWhiteboardJson(true);
//                    runOnUiThread(new Runnable() {
//                        @Override
//                        public void run() {
//                            if (jsonAlertView != null) {
//                                jsonAlertView.setVisibility(View.VISIBLE);
//                            }
//                        }
//                    });

                    handler.postDelayed(() -> {
                        if (jsonAlertView == null) {
                            initJsonAlertView();
                        }
                        jsonAlertView.setVisibility(View.VISIBLE);
                    }, 500);
                }
            }
        }, initDelay, checkPeriod, TimeUnit.MILLISECONDS);

    }

    private void recoverWB() {
//        int i = 0;
//        boolean retry = true;
//        thread.setRunning(false);
//        thread.interrupt();
//        thread.stop();
//        while (retry) {
//            try {
//                thread.join();
//                retry = false;
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//        }
//        thread = null;

        if (surface != null && surface.getHolder().getSurface().isValid()) {
            surface.getHolder().getSurface().release();
        }
        mSettings.setReloadWhiteboardJson(true);
        doRestartApp();
    }

    @Override
    public void whiteboardJsonStringReadyToLoad(String jsonStr, int index) {
        if (jsonStr != null && jsonStr.length() > 0) {
            if (states.get(index) != null) {
                log("Json: load state[" + index + "]");
                WhiteboardState state = states.get(index);

                WhiteboardStateFile stateFile = GsonInstance.getGsonCustomInstance().fromJson(jsonStr, WhiteboardStateFile.class);

                stateFile.loadBaseItemsFromStateFile(stateFile, state.getItems(), getApplicationContext());

                state.setPageColor(stateFile.getColor());
                state.setPagePattern(stateFile.getPattern());
                if (FileHelper.getInstance(getApplicationContext()).getPreviewFile(stateFile.getPreviewFile()).exists()) {
                    state.setPreviewFile(stateFile.getPreviewFile());
                    state.setScreenshotTook(true);
                }
                if (stateFile.getPattern() == PageProperty.Pattern.IMPORT) {
                    state.setCustomBackgroundName(stateFile.getCustomBackgroundName());
                    Bitmap bitmap = stateFileSaver.getJsonImage(stateFile.getCustomBackgroundName());
                    if (bitmap != null) {
                        Drawable background = new BitmapDrawable(getResources(), bitmap);
                        state.setBackgroundDrawable(background);
                    } else {
                        // hitevision debug
                        state.setPagePattern(PageProperty.Pattern.BLANK);
                    }
                }

                state.clearUndoRedoStack();

                if (index == stateIndex && !whiteboard.getState().isAnnotationState()) {
                    whiteboard.queueInput(InputEvent.createSetStateAction(states.get(stateIndex)));
                    runOnUiThread(() -> updatePageNumber(states.get(stateIndex)));
                }
            }
        }
    }

    @Override
    public void annotationJsonStringReadyToLoad(String jsonStr) {
        if (jsonStr != null && jsonStr.length() > 0) {
            if (annotationState != null) {
                WhiteboardStateFile stateFile = GsonInstance.getGsonCustomInstance().fromJson(jsonStr, WhiteboardStateFile.class);

                stateFile.loadBaseItemsFromStateFile(stateFile, annotationState.getItems(), getApplicationContext());

                annotationState.clearUndoRedoStack();

                if (whiteboard.getState().isAnnotationState()) {
                    whiteboard.queueInput(InputEvent.createSetStateAction(annotationState));
                    runOnUiThread(() -> updatePageNumber(annotationState));
                }
            }
        }
    }

    @Override
    public int getCurrentStateSize() {
        return states.size();
    }

    @Override
    public void blockTouchDuringDealingJson(boolean block) {
        runOnUiThread(() -> {
            if (jsonBlockingView == null) {
                initJsonLoadBlockingImageView();
            }
            jsonBlockingView.setVisibility(block ? View.VISIBLE : View.GONE);
        });
    }

    private void saveStateToJson(int index) {
        // hitevision debug
        WhiteboardState state = null;
        if (whiteboard.getState().isAnnotationState()) {
            state = annotationState;
        } else {
            if (stateFileSaver != null && index >= 0) {
                state = states.get(index);
            }
        }

        if (state != null) {
            String jsonFileName = (state.isAnnotationState() ?
                    stateFileSaver.generateAnnotationJsonFileName() : stateFileSaver.generateJsonFileName(index));

            updateStateJson(state, jsonFileName);
        }
    }

    private void updateStateJson(WhiteboardState state, String jsonFileName) {
        if (state != null && jsonFileName != null && jsonFileName.length() > 0) {
            if (state.isPageCustomBackgroundSet() && pageProp.getPattern() == PageProperty.Pattern.IMPORT) {
                if (pageProp.getCustomBackgroundName() == null) {
                    pageProp.generateCustomBackgroundName(String.valueOf(System.currentTimeMillis()));
                }
                if (state.getCustomBackgroundName() == null) {
                    state.setCustomBackgroundName(pageProp.getCustomBackgroundName());
                }
                BitmapDrawable bitmapDrawable = (BitmapDrawable) state.getPageCustomBackground();
                Bitmap bitmap = bitmapDrawable.getBitmap();
                jsonHandler.sendSaveJsonImageToInternal(bitmap, state.getCustomBackgroundName());
            }

            jsonHandler.sendSaveJsonMessage(jsonFileName, state.createStateFile());
            mSettings.setReloadWhiteboardJsonFileSize(states.size());
        }
    }

    private void loadJsonToState() {
        int theLastStateSize = mSettings.getReloadWhiteboardJsonFileSize();

        blockTouchDuringDealingJson(true);

        PageProperty.Color defaultColor = (Props.getFlavorModel().equals(Props.Flavor.Model.Oem) ? PageProperty.Color.GREEN : PageProperty.Color.BLUE);

        if (theLastStateSize > states.size()) {
            int start = states.size();
            for (int i = start; i < theLastStateSize && i < maxNumWhiteboardStates; i++) {
                final WhiteboardState state = new WhiteboardState(defaultColor, PageProperty.Pattern.BLANK, null,
                        fileHelper.generateFileName(false), false);
                states.add(state);
            }

            updatePageNumber(whiteboard.getState());
        }

        jsonHandler.sendLoadJsonToStateMessage();
    }

    private final WhiteboardDialog.OnDialogClickListener onLoadJsonDialogClickListener = (dialog, button) -> {
        if (button == WhiteboardDialog.BUTTON_POSITIVE) {
            String name = mSettings.getJsonSaveFolder();
            stateFileSaver.loadJsonFolder(name);
            loadJsonToState();
        }
    };

    private void showLoadJsonDialog() {
        String oldJsonFolderName = mSettings.getJsonSaveFolder();
        if (oldJsonFolderName == null || oldJsonFolderName.length() == 0) {
            log("Json: no json file saved last time");
            return;
        }

        if (dialog == null) {
            initWhiteboardDialogView();
        }
        dialog.setTitle(getString(R.string.load_json_dialog_title));
        dialog.setContent(getString(R.string.load_json_dialog_content));
        dialog.setPositiveButton(getString(R.string.load_json_ok_btn), onLoadJsonDialogClickListener);
        dialog.setNegativeButton(getString(R.string.load_json_cancel_btn), onLoadJsonDialogClickListener);
        dialog.setVisibility(View.VISIBLE);
    }

    @Override
    public void updateStateJsonFile() {
        saveStateToJson(stateIndex);
    }

    @Override
    public void setMainThreadEraserAreaVisible(boolean visible, float diameter, Whiteboard.Input input) {
        if (eraserAreaView != null) {
            runOnUiThread(() -> {
//                if(diameter > 0){
//                    eraserAreaView.setEraserInput(Whiteboard.Input.PARTIAL_ERASER);
//                }else{
//                    eraserAreaView.setEraserInput(Whiteboard.Input.OBJECT_ERASER);
//                }
                eraserAreaView.setEraserInput(input);
                eraserAreaView.setRadius(diameter / 2);
//                eraserAreaView.setVisibility(visible ? View.VISIBLE : View.GONE);
                if (!FastDraw.isSupportedCanvasFastDrawEraser()) {
                    eraserAreaView.setVisibility(visible ? View.VISIBLE : GONE);
                } else {
                    eraserAreaView.setVisibility(GONE);
                }

            });
        }

//        if(!visible) {
//            whiteboard.resetObjectEraserPen();
//        }

    }

    @Override
    public void reDrawViewOnCanvas(Canvas canvas, int width, int height, Paint paint) {
        if (canvas != null) {
//            if (loginBtnView != null) {
//                canvas.save();
//                canvas.translate(loginBtnView.getX(), loginBtnView.getY());
//                loginBtnView.draw(canvas);
//                canvas.restore();
//            }
//            if (bottomBarShadow != null) {
//                canvas.save();
//                canvas.translate(bottomBarShadow.getX(), bottomBarShadow.getY());
//                bottomBarShadow.draw(canvas);
//                canvas.restore();
//            }
            if (pageNumber != null) {
                canvas.save();
                canvas.translate(pageNumber.getX(), pageNumber.getY());
                pageNumber.draw(canvas);
                canvas.restore();
            }

            if (bottomBarBackground != null) {
                canvas.save();
                canvas.translate(bottomBarBackground.getX(), bottomBarBackground.getY());
                canvas.drawRect(0, 0, bottomBarBackground.getRight(), bottomBarBackground.getBottom(), paint);
                canvas.restore();
            }
        }
    }

    @Override
    public void setMainThreadEraserPosition(PointF p) {
        if (eraserAreaView != null) {
            runOnUiThread(() -> {
                eraserAreaView.updatePosition(p.x, p.y);
            });
        }
    }

    @Override
    public void onEraserRenderOver() {
        if (frontSurfaceView != null) {
            if (frontSurfaceView.getVisibility() == View.VISIBLE) {
                frontSurfaceView.resetEraser();
            } else if (frontSurfaceView.getVisibility() == View.INVISIBLE) {
                runOnUiThread(() -> frontSurfaceView.setVisibility(View.VISIBLE));
            }
        }
        partialEraserDone = true;
    }

    @Override
    public void renderBackgroundFinished() {
        runOnUiThread(() -> {
            fakeBackground.setVisibility(GONE);
        });
    }

    @Override
    public void loadRulerRecord() {
        runOnUiThread(() -> {
            loadMeasurementToolRecordToState(stateIndex);
            updateOptionRulerMenuSelected();
        });
    }

    private void changeDPI(float newDpi) {
        DisplayMetrics metrics = getResources().getDisplayMetrics();
        if (newDpi != metrics.density) {
            log("Dpi is changed to : " + newDpi + ", old dpi : " + metrics.density);
            float scale = metrics.density / newDpi;
            metrics.density /= scale;
            metrics.scaledDensity /= scale;
            metrics.densityDpi = (int) (metrics.densityDpi / scale);
            metrics.xdpi /= scale;
            metrics.ydpi /= scale;
            getResources().getDisplayMetrics().setTo(metrics);
        }
    }


    private static void log(String msg) {
        Log.d(TAG, msg);
    }


    private void initMeasurementToolLayer() {
        ViewStub measurementToolLayerViewStub = findViewById(R.id.measurement_layer_viewstub);
        if (measurementToolLayerViewStub != null && measurementToolLayer == null) {
            measurementToolLayerViewStub.inflate();
            measurementToolLayer = findViewById(R.id.measurement_layer);
        }
    }

    private void updateOptionRulerMenuSelected() {
        if (pluginsToolbarMenuView == null) {
            initPluginsToolbarMenuView();
        }
        if (pluginsToolbarMenuView != null) {
            ArrayList<Boolean> selectedList = new ArrayList<>();
            selectedList.add(ruler != null);
            selectedList.add(rulerTriangle45 != null);
            selectedList.add(rulerTriangle30 != null);
            selectedList.add(protractor180 != null);
            selectedList.add(protractor360 != null);
            selectedList.add(rulerTriangleProtractor != null);
            pluginsToolbarMenuView.updateOptionsRulerIconSelected(selectedList);
        }
    }

    private MeasurementToolListener rulerListener = new MeasurementToolListener() {

        @Override
        public void onDrawingProtractor(float centerX, float centerY, float startX, float startY, float degree, boolean isFinish, int mode) {
            List<PointF> list = new ArrayList<>();
            list.add(new PointF(centerX, centerY));
            list.add(new PointF(startX, startY));
            if (isFinish) {
                whiteboard.queueInput(InputEvent.createProtractorFinish(list, degree, mode));
            } else {
                whiteboard.queueInput(InputEvent.createProtractorDrawing(list, degree, mode));
            }
        }

        @Override
        public void onDrawing(List<PointF> points, boolean isFinish) {
            if (isFinish) {
                whiteboard.queueInput(InputEvent.createRulerFinish(points));
            } else {
                whiteboard.queueInput(InputEvent.createRulerDrawing(points));
            }
        }

        @Override
        public void onClose(String name) {
            if (name.equals(RULER)) {
                removeRulerAndRecord(ruler);
                ruler = null;
            } else if (name.equals(TRIANGLE_RULER_30)) {
                removeRulerAndRecord(rulerTriangle30);
                rulerTriangle30 = null;
            } else if (name.equals(TRIANGLE_RULER_45)) {
                removeRulerAndRecord(rulerTriangle45);
                rulerTriangle45 = null;
            } else if (name.equals(TRIANGLE_PROTRACTOR_RULER)) {
                removeRulerAndRecord(rulerTriangleProtractor);
                rulerTriangleProtractor = null;
            } else if (name.equals(PROTRACTOR_DEGREE_180)) {
                removeRulerAndRecord(protractor180);
                protractor180 = null;
            } else if (name.equals(PROTRACTOR_DEGREE_360)) {
                removeRulerAndRecord(protractor360);
                protractor360 = null;
            }
            updateOptionRulerMenuSelected();
        }

        @Override
        public void updateRecord(String name) {
            WhiteboardState state = states.get(stateIndex);
            if (name.equals(RULER)) {
                state.updateMeasurementToolRecord(ruler);
            } else if (name.equals(TRIANGLE_RULER_30)) {
                state.updateMeasurementToolRecord(rulerTriangle30);
            } else if (name.equals(TRIANGLE_RULER_45)) {
                state.updateMeasurementToolRecord(rulerTriangle45);
            } else if (name.equals(TRIANGLE_PROTRACTOR_RULER)) {
                state.updateMeasurementToolRecord(rulerTriangleProtractor);
            } else if (name.equals(PROTRACTOR_DEGREE_180)) {
                state.updateMeasurementToolRecord(protractor180);
            } else if (name.equals(PROTRACTOR_DEGREE_360)) {
                state.updateMeasurementToolRecord(protractor360);
            }
        }
    };

    private void addMeasurementTool(BasicRuler basicRuler) {
        if (basicRuler != null) {
//            MeasurementToolLayer layer = findViewById(R.id.measurement_tool_layer);
            if (measurementToolLayer == null) {
                initMeasurementToolLayer();
            }
            measurementToolLayer.addRuler(basicRuler);
            addBasicRulerTouchListener(basicRuler);
        }
    }

    private boolean canDrawNewline(Device device) {
        final InputManager inputManager = InputManager.getInstance();
        final Whiteboard.Input input = inputManager.getInput(device);

        if (mSettings.getCurImplementRecognitionMode() == Settings.IMPLEMENT_RECOGNITION_ON_ONLY_PEN) {
            if (device == Device.STYLUS) {
                return input == Whiteboard.Input.PEN || input == Whiteboard.Input.HIGHLIGHTER;
            }
        } else {
            if (device == Device.STYLUS || device == Device.FINGER) {
                return input == Whiteboard.Input.PEN || input == Whiteboard.Input.HIGHLIGHTER;
            }
        }

        return false;
    }

    private void addBasicRulerTouchListener(BasicRuler basicRuler) {
        if (basicRuler != null) {
            basicRuler.setOnTouchListener((v, event) -> {
                final int action = event.getActionMasked();
                final int index = event.getActionIndex();
                final int pointerId = event.getPointerId(index);
                final Device device = TouchUtils.getEventDevice(MainActivity.this, pointerId, event);
                final Whiteboard.Input input = InputManager.getInstance().getInput(device);

                if (action == MotionEvent.ACTION_DOWN) {
                    MainActivity.this.hideMenus();
                    whiteboard.setDevice(pointerId, device);
                    if (input == Whiteboard.Input.PEN) {
                        PenProperty penProperty = device == Device.STYLUS ? stylusPenProp : fingerPenProp;
                        basicRuler.setDrawingLineWidth(penProperty.getStrokeWidth() * states.get(stateIndex).getAppliedScale());
                    } else if (input == Whiteboard.Input.HIGHLIGHTER) {
                        HighlighterProperty highlighterProperty = device == Device.STYLUS ? stylusHighlighterProp : fingerHighlighterProp;
                        basicRuler.setDrawingLineWidth(highlighterProperty.getStrokeWidth() * states.get(stateIndex).getAppliedScale());
                    }
                }

                return basicRuler.rulerOnTouch(v, event, MainActivity.this.canDrawNewline(device));
            });
        }
    }

    private void hideRulers() {
        if (measurementToolLayer == null) {
            initMeasurementToolLayer();
        }
        measurementToolLayer.removeRuler(ruler);
        measurementToolLayer.removeRuler(rulerTriangle30);
        measurementToolLayer.removeRuler(rulerTriangle45);
        measurementToolLayer.removeRuler(protractor180);
        measurementToolLayer.removeRuler(protractor360);
        measurementToolLayer.removeRuler(rulerTriangleProtractor);
        ruler = null;
        rulerTriangle30 = null;
        rulerTriangle45 = null;
        protractor180 = null;
        protractor360 = null;
        rulerTriangleProtractor = null;
    }

    private void loadMeasurementToolRecordToState(int index) {
        if (index >= states.size() || states.get(index) == null) {
            return;
        }
        hideRulers();
        WhiteboardState state = states.get(index);
        assert state != null;
        if (measurementToolLayer == null) {
            initMeasurementToolLayer();
        }
        BasicRuler[] list = state.loadMeasurementToolRecord(getBaseContext(), measurementToolLayer, rulerListener);
        ruler = (Ruler) list[0];
        rulerTriangle30 = (RulerTriangle) list[1];
        rulerTriangle45 = (RulerTriangle) list[2];
        protractor180 = (Protractor) list[3];
        protractor360 = (Protractor) list[4];
        rulerTriangleProtractor = (RulerTriangle) list[5];
        for (int i = 0; i < list.length; i++) {
            addBasicRulerTouchListener(list[i]);
        }
    }

    private void removeRulerAndRecord(BasicRuler ruler) {
//        MeasurementToolLayer layer = findViewById(R.id.measurement_tool_layer);
        if (measurementToolLayer == null) {
            initMeasurementToolLayer();
        }
        measurementToolLayer.removeRuler(ruler);
        states.get(stateIndex).removeMeasurementToolRecord(ruler);
    }

    private void initOptionsMenuView() {
        if (null != optionsRulerMenuView) {
            return;
        }
        pluginsToolbarMenuView.setInit(optionsListener, toggleInputTouchListener);
        viewStubRulerMenuView.inflate();
        optionsRulerMenuView = findViewById(R.id.options_ruler_menu_view);
        optionsRulerMenuView.setVisibility(View.GONE);
        optionsRulerMenuView.setListener(name -> {
            if (optionsListener != null) {
                optionsListener.OnItemClick(name);
            }
        });
        optionsRulerMenuView.setOnTouchListener((v, event) -> {
            optionsRulerMenuView.onTouch(optionsRulerMenuView, event);
            return false;
        });

    }

    public void NewMethodForTakeScrennShot() {
        Intent intent = new Intent();
        intent.setComponent(new ComponentName("com.hht.hhtscreenshot", "com.hht.hhtscreenshot.ScreenShotService"));
        startService(intent);
    }
    private OptionsRecyclerViewAdapter.OptionsRecyclerViewItemListener optionsListener = new OptionsRecyclerViewAdapter.OptionsRecyclerViewItemListener() {
        @Override
        public void OnItemClick(String options) {
            if (options.equals(getApplicationContext().getString(R.string.plugin_app_rulers))) {
                optionsRulerMenuView.setVisibility(VISIBLE);
            } else if (options.equals(RULER)) {
                if (ruler == null || ruler.getVisibility() != VISIBLE) {
                    ruler = new Ruler(getBaseContext(), rulerListener);
                    addMeasurementTool(ruler);
                    states.get(stateIndex).updateMeasurementToolRecord(ruler);
                } else {
                    removeRulerAndRecord(ruler);
                    ruler = null;
                }
            } else if (options.equals(TRIANGLE_RULER_30)) {
                if (rulerTriangle30 == null || rulerTriangle30.getVisibility() != VISIBLE) {
                    rulerTriangle30 = new RulerTriangle(getBaseContext(), RulerTriangle.TriangleType.DEGREE30, rulerListener);
                    addMeasurementTool(rulerTriangle30);
                    states.get(stateIndex).updateMeasurementToolRecord(rulerTriangle30);
                } else {
                    removeRulerAndRecord(rulerTriangle30);
                    rulerTriangle30 = null;
                }
            } else if (options.equals(TRIANGLE_RULER_45)) {
                if (rulerTriangle45 == null || rulerTriangle45.getVisibility() != VISIBLE) {
                    rulerTriangle45 = new RulerTriangle(getBaseContext(), RulerTriangle.TriangleType.DEGREE45, rulerListener);
                    addMeasurementTool(rulerTriangle45);
                    states.get(stateIndex).updateMeasurementToolRecord(rulerTriangle45);
                } else {
                    removeRulerAndRecord(rulerTriangle45);
                    rulerTriangle45 = null;
                }
            } else if (options.equals(TRIANGLE_PROTRACTOR_RULER)) {
                if (rulerTriangleProtractor == null || rulerTriangleProtractor.getVisibility() != VISIBLE) {
                    rulerTriangleProtractor = new RulerTriangle(getBaseContext(), RulerTriangle.TriangleType.TRIANGLE_PROTRACTOR, rulerListener);
                    addMeasurementTool(rulerTriangleProtractor);
                    states.get(stateIndex).updateMeasurementToolRecord(rulerTriangleProtractor);
                } else {
                    removeRulerAndRecord(rulerTriangleProtractor);
                    rulerTriangleProtractor = null;
                }
            } else if (options.equals(PROTRACTOR_DEGREE_180)) {
                if (protractor180 == null || protractor180.getVisibility() != VISIBLE) {
                    protractor180 = new Protractor(getBaseContext(), Protractor.ProtractorMode.DEGREE180, rulerListener);
                    addMeasurementTool(protractor180);
                    states.get(stateIndex).updateMeasurementToolRecord(protractor180);
                } else {
                    removeRulerAndRecord(protractor180);
                    protractor180 = null;
                }
            } else if (options.equals(PROTRACTOR_DEGREE_360)) {
                if (protractor360 == null || protractor360.getVisibility() != VISIBLE) {
                    protractor360 = new Protractor(getBaseContext(), Protractor.ProtractorMode.DEGREE360, rulerListener);
                    addMeasurementTool(protractor360);
                    states.get(stateIndex).updateMeasurementToolRecord(protractor360);
                } else {
                    removeRulerAndRecord(protractor360);
                    protractor360 = null;
                }
            }
        }
    };
}
